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 explain
wyniki. 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. id
jest 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)
źródło
SHOW CREATE TABLE
i prawdopodobnieEXPLAIN...
też.email
jest niezindeksowane, następnie obieDELETE
iSELECT
powinny działać równie powolny. Lub: Mówisz, że tabela jest mocno zadawana. Może kiedy próbowałeś pierwszego,DELETE
ktoś inny przeprowadzał naprawdę długą transakcję w tych rzędach ...DELETE FROM ThreadNotification2 WHERE email='invalid address';
może też pomogłoby ...EXPLAIN DELETE FROM....
, to nie zadziała. Z tego co wiem, działa tylko naSELECT
s.Odpowiedzi:
Jeśli pole
email
jest niezindeksowane, następnie obieDELETE
iSELECT
powinny 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.
źródło