为什么DELETE比SELECT慢得多,然后按ID进行DELETE?


12

我有一个非常繁忙的InnoDB表(200,000行,我猜每秒大概有几十个查询)。由于一个错误,我得到了14行,其中包含(相同)无效的电子邮件地址,并希望将其删除。

我只是尝试DELETE FROM table WHERE email='invalid address'了一下,并在大约50秒后得到了“超出了锁定等待超时”。这并不奇怪,因为未对行列进行索引。

但是,然后我做了SELECT id FROM table WHERE email='invalid address',那花了1.25秒。运行DELETE FROM table WHERE id in (...),从SELECT结果中复制粘贴ID,花费了0.02秒。

到底是怎么回事?有人可以解释为什么带有条件的DELETE这么慢以至于超时,但是执行SELECT然后按ID删除却是如此之快吗?

谢谢。

编辑:根据要求,我发布了表结构以及一些explain结果。我还应注意,没有任何外键引用此表。

但是,这种情况对我来说似乎很简单:我有一个未索引的字段可供选择。这需要扫描整个表,但是它并不大。id是主键,因此按ID删除应该是非常快速的。

mysql> show create table ThreadNotification2 \G
*************************** 1. row ***************************
       Table: ThreadNotification2
Create Table: CREATE TABLE `ThreadNotification2` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `alertId` bigint(20) DEFAULT NULL,
  `day` int(11) NOT NULL,
  `frequency` int(11) DEFAULT NULL,
  `hour` int(11) NOT NULL,
  `email` varchar(255) DEFAULT NULL,
  `highlightedTitle` longtext,
  `newReplies` bit(1) NOT NULL,
  `numReplies` int(11) NOT NULL,
  `postUrl` longtext,
  `sendTime` datetime DEFAULT NULL,
  `sent` bit(1) NOT NULL,
  `snippet` longtext,
  `label_id` bigint(20) DEFAULT NULL,
  `organization_id` bigint(20) DEFAULT NULL,
  `threadEntity_hash` varchar(255) DEFAULT NULL,
  `user_uid` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK3991E9D279251FE` (`organization_id`),
  KEY `FK3991E9D35FC0C96` (`label_id`),
  KEY `FK3991E9D3FFC22CB` (`user_uid`),
  KEY `FK3991E9D5376B351` (`threadEntity_hash`),
  KEY `scheduleSentReplies` (`day`,`frequency`,`hour`,`sent`,`numReplies`),
  KEY `sendTime` (`sendTime`),
  CONSTRAINT `FK3991E9D279251FE` FOREIGN KEY (`organization_id`) REFERENCES `Organization` (`id`),
  CONSTRAINT `FK3991E9D35FC0C96` FOREIGN KEY (`label_id`) REFERENCES `Label` (`id`),
  CONSTRAINT `FK3991E9D3FFC22CB` FOREIGN KEY (`user_uid`) REFERENCES `User` (`uid`),
  CONSTRAINT `FK3991E9D5376B351` FOREIGN KEY (`threadEntity_hash`) REFERENCES `ThreadEntity` (`hash`)
) ENGINE=InnoDB AUTO_INCREMENT=4461945 DEFAULT CHARSET=utf8
1 row in set (0.08 sec)

mysql> explain SELECT * FROM ThreadNotification2 WHERE email='invalid address';
+----+-------------+---------------------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table               | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+---------------------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | ThreadNotification2 | ALL  | NULL          | NULL | NULL    | NULL | 197414 | Using where |
+----+-------------+---------------------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.03 sec)


mysql> explain select * from ThreadNotification2 where id in (3940042,3940237,3941132,3941255,3941362,3942535,3943064,3944134,3944228,3948122,3953081,3957876,3963849,3966951);
+----+-------------+---------------------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table               | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+---------------------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | ThreadNotification2 | range | PRIMARY       | PRIMARY | 8       | NULL |   14 | Using where |
+----+-------------+---------------------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)



mysql> delete from ThreadNotification2 where email='invalid address';
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> select id from ThreadNotification2 where email='invalid address';
+---------+
| id      |
+---------+
| 3940042 |
| 3940237 |
| 3941132 |
| 3941255 |
| 3941362 |
| 3942535 |
| 3943064 |
| 3944134 |
| 3944228 |
| 3948122 |
| 3953081 |
| 3957876 |
| 3963849 |
| 3966951 |
+---------+
14 rows in set (1.25 sec)

mysql> delete from ThreadNotification2 where id in (3940042,3940237,3941132,3941255,3941362,3942535,3943064,3944134,3944228,3948122,3953081,3957876,3963849,3966951);
Query OK, 14 rows affected (0.02 sec)

2
我猜您绝对必须发布一个SHOW CREATE TABLE,也可能发布一个EXPLAIN...
Radu Murzea 2012年

@SoboLAN真的吗?似乎是一个简单的场景。我更新了问题。
itsadok

是的,但是。。。。如果该字段email未建立索引,则两者DELETESELECT都应同样缓慢地工作。或者:您说桌子查询过多。也许当您第一次尝试时,DELETE就有其他人在这些行上进行了非常长的交易...
Radu Murzea 2012年

另一种解释DELETE FROM ThreadNotification2 WHERE email='invalid address';也许也会有所帮助...
pconcepcion 2012年

@pconcepcion如果您编写EXPLAIN DELETE FROM....,它将无法正常工作。据我所知,它仅适用于SELECT
Radu Murzea 2012年

Answers:


6

如果该字段email未建立索引,则两者DELETESELECT都应同样缓慢地工作。

我能想到的唯一可能性是:您说该表已被大量访问。在您尝试执行时,也许其他人运行了很长的事务(直接或间接涉及那些特定的行)DELETE

我认为也许您应该在其中插入一些模拟行,然后尝试将其删除。这样做2或3次。如果的持续时间有很大差异DELETE,则可能是DB负载。

PS:只有当人们不会被那些嘲笑的行烦恼时才这样做:D。


2
你的答案是“我不知道为什么”吗?
Pacerier,2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.