Warum ist DELETE so viel langsamer als SELECT, dann DELETE by id?

12

Ich habe eine ziemlich ausgelastete InnoDB-Tabelle (200.000 Zeilen, ich denke so etwas wie Dutzende von Abfragen pro Sekunde). Aufgrund eines Fehlers habe ich 14 Zeilen mit (denselben) ungültigen E-Mail-Adressen erhalten und wollte diese löschen.

Ich habe einfach versucht DELETE FROM table WHERE email='invalid address'und nach ca. 50 Sekunden "Wartezeitüberschreitung der Sperre überschritten". Dies ist nicht besonders überraschend, da die Zeilenspalte nicht indiziert ist.

Allerdings habe ich das dann gemacht SELECT id FROM table WHERE email='invalid address'und das hat 1,25 Sekunden gedauert. Das Ausführen DELETE FROM table WHERE id in (...), Kopieren und Einfügen der IDs aus dem SELECT-Ergebnis, dauerte 0,02 Sekunden.

Was ist los? Kann jemand erklären, warum das LÖSCHEN mit der Bedingung so langsam ist, dass die Zeit abläuft, aber SELECT auszuführen und dann nach ID zu löschen, ist so schnell?

Vielen Dank.

EDIT: Auf Wunsch habe ich die Tabellenstruktur sowie einige explainErgebnisse gepostet . Ich sollte auch beachten, dass es keine Fremdschlüssel gibt, die auf diese Tabelle verweisen.

Die Situation scheint mir jedoch einfach zu sein: Ich habe ein nicht indiziertes Feld, gegen das ich mich wähle. Dies erfordert das Scannen des gesamten Tisches, ist jedoch nicht besonders groß. idist der Primärschlüssel, daher ist das Löschen nach ID sehr schnell, wie es sein sollte.

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
quelle
2
Ich denke du musst unbedingt einen posten SHOW CREATE TABLEund wahrscheinlich auch einen EXPLAIN....
Radu Murzea
@SoboLAN wirklich? Es scheint so ein einfaches Szenario zu sein. Ich habe die Frage aktualisiert.
Itsadok
Ja, aber ... du hattest an erster Stelle recht. Wenn das Feld nicht emailindiziert ist, sollten beide DELETEund SELECTgleich langsam arbeiten. Oder: Sie sagen, dass die Tabelle stark abgefragt wird. Vielleicht hat bei Ihrem ersten Versuch DELETEjemand anderes eine wirklich lange Transaktion in diesen Zeilen ausgeführt ...
Radu Murzea
Eine andere Erklärung von DELETE FROM ThreadNotification2 WHERE email='invalid address';vielleicht würde auch helfen ...
pconcepcion
@pconcepcion Wenn Sie schreiben EXPLAIN DELETE FROM...., wird es nicht funktionieren. Soweit ich weiß, funktioniert es nur auf SELECTs.
Radu Murzea

Antworten:

6

Wenn das Feld nicht emailindiziert ist, sollten beide DELETEund SELECTgleich langsam arbeiten.

Die einzige Möglichkeit, an die ich denken kann, ist: Sie sagen, dass auf die Tabelle stark zugegriffen wird. Möglicherweise hat eine andere Person eine sehr lange Transaktion ausgeführt (die direkt oder indirekt diese bestimmten Zeilen einbezieht), während Sie versuchten, die auszuführen DELETE.

Ich denke, vielleicht sollten Sie dort einige Scheinzeilen einfügen und versuchen, sie zu löschen. Mach das 2 oder 3 mal. Wenn es einen großen Unterschied in der Dauer der gibt DELETE, dann ist die DB-Last wahrscheinlich der Grund.

PS: Tun Sie das nur, wenn die Leute sich nicht über diese Scheinreihen ärgern: D.

Radu Murzea
quelle
2
Also ist Ihre Antwort "Ich weiß nicht warum"?
Pacerier