Чому DELETE набагато повільніше, ніж SELECT, а потім 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, зайняв 0,02 секунди.

Що відбувається? Чи може хтось пояснити, чому DELETE з умовою настільки повільний, що він вичерпується, але робити SELECT та видалити за допомогою id так швидко?

Дякую.

EDIT: За запитом я опублікував структуру таблиці, а також деякі 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...теж.
Раду Мурзеа

@SoboLAN насправді? Схоже, такий простий сценарій. Я оновив питання.
itadok

Так, але .... ви були в першу чергу праві. Якщо поле emailнеприєднане, то обидва DELETEі SELECTповинні працювати однаково повільно. Або: Ви кажете, що таблиця сильно запитується. Можливо, коли ви спробували свій перший, DELETEхтось інший
здійснив

Ще одне пояснення, DELETE FROM ThreadNotification2 WHERE email='invalid address';можливо, допоможе також ...
pconcepcion

@pconcepcion, якщо ви пишете EXPLAIN DELETE FROM...., це не працюватиме. З того, що мені відомо, він працює лише на SELECTs.
Раду Мурзеа

Відповіді:


6

Якщо поле emailнеприєднане, то обидва DELETEі SELECTповинні працювати однаково повільно.

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

Я думаю, можливо, вам слід вставити туди кілька макетних рядків і спробувати їх видалити. Зробіть це 2 або 3 рази. Якщо є велика різниця в тривалості DELETE, то, мабуть, причина завантаження БД.

PS: Робіть це лише в тому випадку, якщо людей не будуть дратувати ці макетні рядки: D.


2
Тож ваша відповідь "я не знаю чому"?
Пейс’єр
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.