¿Por qué DELETE es mucho más lento que SELECT, luego DELETE by id?

12

Tengo una tabla InnoDB bastante ocupada (200,000 filas, supongo que algo así como decenas de consultas por segundo). Debido a un error, obtuve 14 filas con (la misma) direcciones de correo electrónico no válidas y quería eliminarlas.

Simplemente intenté DELETE FROM table WHERE email='invalid address'y obtuve el "Tiempo de espera de bloqueo excedido" después de unos 50 segundos. Esto no es terriblemente sorprendente, ya que la columna de la fila no está indexada.

Sin embargo, luego lo hice SELECT id FROM table WHERE email='invalid address'y eso tomó 1.25 segundos. Ejecutar DELETE FROM table WHERE id in (...), copiar y pegar los identificadores del resultado SELECCIONAR, tomó 0.02 segundos.

Que esta pasando? ¿Alguien puede explicar por qué ELIMINAR con la condición es tan lento que agota el tiempo de espera, pero hacer SELECCIONAR y luego eliminar por id es tan rápido?

Gracias.

EDITAR: Por solicitud, publiqué la estructura de la tabla y algunos explainresultados. También debo tener en cuenta que no hay claves foráneas que se refieran a esta tabla.

Sin embargo, la situación me parece sencilla: tengo un campo no indexado con el que estoy seleccionando. Esto requiere escanear toda la tabla, pero no es terriblemente grande. ides la clave principal, por lo que eliminar por id es muy rápido, como debería ser.

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
fuente
2
Supongo que absolutamente debes publicar un SHOW CREATE TABLEy probablemente un EXPLAIN...también.
Radu Murzea
@SoboLAN realmente? Parece un escenario tan simple. Actualicé la pregunta.
itsadok
Sí, pero ... tenías razón en primer lugar. Si el campo emailes no indexados, entonces ambos DELETEy SELECTdebería funcionar igualmente lento. O bien: Usted dice que la mesa está muy consultada. Tal vez cuando DELETE
probaste por
Otra explicación de DELETE FROM ThreadNotification2 WHERE email='invalid address';quizás ayudaría también ...
pconcepcion
@pconcepcion si escribes EXPLAIN DELETE FROM...., no funcionará. Por lo que sé, funciona solo en SELECTs.
Radu Murzea

Respuestas:

6

Si el campo emailes no indexados, entonces ambos DELETEy SELECTdebería funcionar igualmente lento.

La única posibilidad que se me ocurre es: usted dice que se accede mucho a la tabla. Tal vez alguien más ejecutó una transacción muy larga (que involucra directa o indirectamente esas filas específicas) mientras intentaba ejecutar el DELETE.

Creo que tal vez deberías insertar algunas filas simuladas allí e intentar eliminarlas. Haz eso 2 o 3 veces. Si hay una gran diferencia en la duración de la DELETE, entonces la carga de DB es probablemente la razón.

PD: Haz eso solo si las personas no se molestarán por esas filas simuladas: D.

Radu Murzea
fuente
2
Entonces, ¿es tu respuesta "No sé por qué"?
Pacerier