Почему DELETE намного медленнее, чем SELECT, а затем DELETE по id?

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 занял 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)
itsadok
источник
2
Я думаю, вы обязательно должны опубликовать SHOW CREATE TABLEи, вероятно, EXPLAIN...тоже.
Раду Мурзеа
@ Соболан правда? Это похоже на такой простой сценарий. Я обновил вопрос.
itadok
Да, но .... ты был прав в первую очередь. Если поле emailнеиндексировано, то оба DELETEи SELECTдолжны работать одинаково медленно. Или: Вы говорите, что к столу очень много запросов. Может быть, когда вы попробовали в первый раз, DELETEкто-то еще выполнял действительно длинную транзакцию в этих рядах ...
Раду Мурзе
Еще одно объяснение, DELETE FROM ThreadNotification2 WHERE email='invalid address';возможно, могло бы помочь также ...
pconcepcion
@pconcepcion, если вы напишите EXPLAIN DELETE FROM...., это не сработает. Из того, что я знаю, это работает только на SELECTс.
Раду Мурзеа

Ответы:

6

Если поле emailнеиндексировано, то оба DELETEи SELECTдолжны работать одинаково медленно.

Единственная возможность, о которой я могу подумать: вы говорите, что к столу есть большой доступ. Может быть, кто-то еще выполнил очень длинную транзакцию (с прямым или косвенным использованием этих конкретных строк), пока вы пытались выполнить DELETE.

Я думаю, может быть, вы должны вставить туда несколько макетов и попытаться удалить их. Сделайте это 2 или 3 раза. Если есть большая разница в продолжительности DELETE, то, вероятно, причина в загрузке БД.

PS: Делайте это только в том случае, если люди не будут раздражены этими насмешливыми рядами: D.

Раду Мурзеа
источник
2
Так ваш ответ "я не знаю почему"?
Pacerier