Mengapa DELETE jauh lebih lambat daripada SELECT, lalu DELETE oleh id?

12

Saya memiliki tabel InnoDB yang cukup sibuk (200.000 baris, saya kira kira-kira puluhan pertanyaan per detik). Karena bug, saya mendapat 14 baris dengan alamat email (yang sama) tidak valid di dalamnya dan ingin menghapusnya.

Saya hanya mencoba DELETE FROM table WHERE email='invalid address'dan mendapatkan "Batas waktu tunggu tunggu melebihi" setelah sekitar 50 detik. Ini tidak terlalu mengejutkan, karena kolom baris tidak diindeks.

Namun, saya kemudian melakukannya SELECT id FROM table WHERE email='invalid address'dan itu butuh 1,25 detik. Menjalankan DELETE FROM table WHERE id in (...), menyalin-menempelkan id dari hasil SELECT, butuh 0,02 detik.

Apa yang sedang terjadi? Adakah yang bisa menjelaskan mengapa DELETE dengan kondisinya sangat lambat sehingga tidak aktif, tetapi melakukan SELECT dan kemudian menghapus dengan id begitu cepat?

Terima kasih.

EDIT: Atas permintaan, saya memposting struktur tabel serta beberapa explainhasil. Saya juga harus mencatat bahwa tidak ada kunci asing yang merujuk pada tabel ini.

Namun, situasinya tampak langsung bagi saya: Saya memiliki bidang yang tidak tereksplorasi yang saya pilih. Ini membutuhkan pemindaian seluruh tabel, tetapi itu tidak terlalu besar. idadalah kunci utama, jadi menghapus dengan id sangat cepat, sebagaimana mestinya.

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
sumber
2
Saya kira Anda benar-benar harus memposting SHOW CREATE TABLEdan mungkin EXPLAIN...juga.
Radu Murzea
@ SoboLAN benar-benar? Sepertinya ini skenario yang sederhana. Saya memperbarui pertanyaan.
itsadok
Ya tapi .... Anda benar sejak awal. Jika bidang emailtidak terindeks, maka keduanya DELETEdan SELECTharus bekerja sama lambat. Atau: Anda mengatakan bahwa tabel itu sangat ditanyakan. Mungkin ketika Anda mencoba pertama Anda DELETEada orang lain menjalankan transaksi yang sangat panjang pada baris-baris itu ...
Radu Murzea
DELETE FROM ThreadNotification2 WHERE email='invalid address';
Penjelasan
@ pconcepcion jika Anda menulis EXPLAIN DELETE FROM...., itu tidak akan berfungsi. Dari apa yang saya tahu, ini hanya berfungsi pada SELECTs.
Radu Murzea

Jawaban:

6

Jika bidang emailtidak terindeks, maka keduanya DELETEdan SELECTharus bekerja sama lambat.

Satu-satunya kemungkinan yang dapat saya pikirkan adalah: Anda mengatakan bahwa tabel tersebut sangat diakses. Mungkin orang lain menjalankan transaksi yang sangat panjang (melibatkan langsung atau tidak langsung baris-baris spesifik itu) ketika Anda mencoba untuk mengeksekusi DELETE.

Saya pikir mungkin Anda harus memasukkan beberapa baris tiruan di sana dan mencoba untuk menghapusnya. Lakukan itu 2 atau 3 kali. Jika ada perbedaan besar dalam durasi DELETE, maka beban DB mungkin menjadi alasannya.

PS: Lakukan itu hanya jika orang tidak akan terganggu oleh baris tiruan itu: D.

Radu Murzea
sumber
2
Jadi, apakah jawaban Anda "Saya tidak tahu mengapa"?
Pacerier