Dlaczego DELETE jest o wiele wolniejsze niż SELECT, a następnie DELETE id?

12

Mam dość zajętą ​​tabelę InnoDB (200 000 wierszy, chyba coś w rodzaju dziesiątek zapytań na sekundę). Z powodu błędu otrzymałem 14 wierszy z (tymi samymi) nieprawidłowymi adresami e-mail i chciałem je usunąć.

Po prostu spróbowałem DELETE FROM table WHERE email='invalid address'i po około 50 sekundach przekroczono limit czasu oczekiwania na zablokowanie. Nie jest to zaskakujące, ponieważ kolumna wiersza nie jest indeksowana.

Jednak zrobiłem to SELECT id FROM table WHERE email='invalid address'i zajęło to 1,25 sekundy. Uruchamianie DELETE FROM table WHERE id in (...), kopiowanie i wklejanie identyfikatorów z wyniku SELECT zajęło 0,02 sekundy.

Co się dzieje? Czy ktoś może wyjaśnić, dlaczego DELETE z warunkiem jest tak wolne, że upływa limit czasu, ale wykonanie instrukcji SELECT, a następnie usunięcie według identyfikatora jest tak szybkie?

Dzięki.

EDYCJA: Na żądanie opublikowałem strukturę tabeli, a także niektóre explainwyniki. Powinienem również zauważyć, że nie ma obcych kluczy odnoszących się do tej tabeli.

Sytuacja wydaje mi się jednak prosta: mam nieindeksowane pole, przeciwko któremu wybieram. Wymaga to przeskanowania całego stołu, ale nie jest on strasznie duży. idjest kluczem podstawowym, więc usuwanie id jest bardzo szybkie, jak powinno być.

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
źródło
2
Myślę, że absolutnie musisz opublikować SHOW CREATE TABLEi prawdopodobnie EXPLAIN...też.
Radu Murzea,
@SoboLAN naprawdę? Wydaje się, że to taki prosty scenariusz. Zaktualizowałem pytanie.
itsadok
Tak, ale .... miałeś rację w pierwszej kolejności. Jeśli pole emailjest niezindeksowane, następnie obie DELETEi SELECTpowinny działać równie powolny. Lub: Mówisz, że tabela jest mocno zadawana. Może kiedy próbowałeś pierwszego, DELETEktoś inny przeprowadzał naprawdę długą transakcję w tych rzędach ...
Radu Murzea,
Kolejne wyjaśnienie DELETE FROM ThreadNotification2 WHERE email='invalid address';może też pomogłoby ...
pconcepcion
@pconcepcion, jeśli napiszesz EXPLAIN DELETE FROM...., to nie zadziała. Z tego co wiem, działa tylko na SELECTs.
Radu Murzea,

Odpowiedzi:

6

Jeśli pole emailjest niezindeksowane, następnie obie DELETEi SELECTpowinny działać równie powolny.

Jedyną możliwością, jaką mogę wymyślić, jest: Mówisz, że dostęp do stołu jest duży. Być może ktoś inny przeprowadził bardzo długą transakcję (obejmującą bezpośrednio lub pośrednio te konkretne wiersze) podczas próby wykonania DELETE.

Myślę, że może powinieneś wstawić tam kilka próbnych wierszy i spróbować je usunąć. Zrób to 2 lub 3 razy. Jeśli istnieje duża różnica w czasie trwania DELETE, prawdopodobnie przyczyną jest obciążenie DB.

PS: Rób to tylko wtedy, gdy ludzie nie będą zirytowani tymi fałszywymi wierszami: D.

Radu Murzea
źródło
2
Więc twoja odpowiedź „nie wiem dlaczego”?
Pacerier