Perché DELETE è molto più lento di SELECT, quindi DELETE per ID?


12

Ho una tabella InnoDB abbastanza occupata (200.000 righe, immagino qualcosa come decine di query al secondo). A causa di un bug ho ricevuto 14 righe con (gli stessi) indirizzi e-mail non validi e volevo eliminarli.

Ho semplicemente provato DELETE FROM table WHERE email='invalid address'e ho superato il "Timeout attesa blocco" dopo circa 50 secondi. Ciò non è terribilmente sorprendente, poiché la colonna della riga non è indicizzata.

Tuttavia, l'ho fatto SELECT id FROM table WHERE email='invalid address'e ci sono voluti 1,25 secondi. L'esecuzione DELETE FROM table WHERE id in (...), il copia-incolla degli ID dal risultato SELECT, ha richiesto 0,02 secondi.

Cosa sta succedendo? Qualcuno può spiegare perché ELIMINA con la condizione è così lenta da andare in timeout, ma fare SELEZIONA e poi cancellare con ID è così veloce?

Grazie.

EDIT: su richiesta, ho pubblicato la struttura della tabella e alcuni explainrisultati. Dovrei anche notare che non ci sono chiavi esterne che fanno riferimento a questa tabella.

Tuttavia, la situazione mi sembra semplice: ho un campo inesplorato che sto selezionando contro. Ciò richiede la scansione dell'intero tavolo, ma non è terribilmente grande. idè la chiave primaria, quindi l'eliminazione tramite id è molto rapida, come dovrebbe essere.

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
Immagino che tu debba assolutamente pubblicare un SHOW CREATE TABLEe probabilmente EXPLAIN...anche un .
Radu Murzea,

@SoboLAN davvero? Sembra uno scenario così semplice. Ho aggiornato la domanda.
Ha iniziato il

Sì, ma ... avevi ragione in primo luogo. Se il campo non emailè indicizzato, entrambi DELETEe SELECTdovrebbero funzionare altrettanto lentamente. Oppure: dici che il tavolo è interrogato pesantemente. Forse quando hai provato per la prima volta DELETEc'era qualcun altro che stava eseguendo una transazione davvero lunga su quelle file ...
Radu Murzea,

Un'altra spiegazione di DELETE FROM ThreadNotification2 WHERE email='invalid address';forse aiuterebbe anche ...
pconcepcion il

@pconcepcion se scrivi EXPLAIN DELETE FROM...., non funzionerà. Da quello che so, funziona solo su SELECTs.
Radu Murzea,

Risposte:


6

Se il campo non emailè indicizzato, entrambi DELETEe SELECTdovrebbero funzionare altrettanto lentamente.

L'unica possibilità che mi viene in mente è: dici che si accede pesantemente al tavolo. Forse qualcun altro ha eseguito una transazione molto lunga (coinvolgendo direttamente o indirettamente quelle righe specifiche) mentre stavi tentando di eseguire il file DELETE.

Penso che forse dovresti inserire alcune righe finte lì e provare a eliminarle. Fallo 2 o 3 volte. Se c'è una grande differenza nella durata del DELETE, allora il carico del DB è probabilmente il motivo.

PS: Fallo solo se le persone non saranno infastidite da quelle file finte: D.


2
Quindi la tua risposta è "Non so perché"?
Pacerier,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.