Tại sao XÓA lại chậm hơn nhiều so với CHỌN, sau đó XÓA theo id?


12

Tôi có một bảng InnoDB khá bận rộn (200.000 hàng, tôi đoán có gì đó giống như hàng chục truy vấn mỗi giây). Do một lỗi, tôi có 14 hàng với (cùng) địa chỉ email không hợp lệ trong đó và muốn xóa chúng.

Tôi chỉ đơn giản là đã thử DELETE FROM table WHERE email='invalid address'và nhận được "Khóa thời gian chờ vượt quá" sau khoảng 50 giây. Điều này không đáng ngạc nhiên lắm, vì cột hàng không được lập chỉ mục.

Tuy nhiên, sau đó tôi đã làm SELECT id FROM table WHERE email='invalid address'và điều đó mất 1,25 giây. Chạy DELETE FROM table WHERE id in (...), dán sao chép id từ kết quả CHỌN, mất 0,02 giây.

Chuyện gì đang xảy ra vậy? Ai đó có thể giải thích lý do tại sao XÓA với điều kiện chậm đến mức hết thời gian không, nhưng thực hiện CHỌN và sau đó xóa bằng id quá nhanh?

Cảm ơn.

EDIT: Theo yêu cầu, tôi đã đăng cấu trúc bảng cũng như một số explainkết quả. Tôi cũng cần lưu ý rằng không có khóa ngoại nào đề cập đến bảng này.

Tuy nhiên, tình huống có vẻ đơn giản với tôi: Tôi có một lĩnh vực chưa được tìm hiểu mà tôi đang chọn. Điều này đòi hỏi phải quét toàn bộ bảng, nhưng nó không quá lớn. idlà khóa chính, vì vậy việc xóa bằng id rất nhanh chóng.

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
Tôi đoán bạn hoàn toàn phải đăng một SHOW CREATE TABLEvà có lẽ là EXPLAIN...quá.
Radu Murzea

@Sobolan thực sự? Có vẻ như một kịch bản đơn giản như vậy. Tôi cập nhật câu hỏi.
itadok

Vâng nhưng .... bạn đã đúng ngay từ đầu. Nếu trường không emailđược lập chỉ mục, thì cả hai DELETESELECTsẽ hoạt động chậm như nhau. Hoặc: Bạn nói rằng bảng được truy vấn rất nhiều. Có thể khi bạn thử lần đầu tiên, DELETEcó một người khác đang thực hiện một giao dịch thực sự dài trên các hàng đó ...
Radu Murzea

Một cách giải thích khác DELETE FROM ThreadNotification2 WHERE email='invalid address';có lẽ cũng sẽ giúp ...
pconcepcion

@pconcepcion nếu bạn viết EXPLAIN DELETE FROM...., nó sẽ không hoạt động. Từ những gì tôi biết, nó chỉ hoạt động trên SELECTs.
Radu Murzea

Câu trả lời:


6

Nếu trường không emailđược lập chỉ mục, thì cả hai DELETESELECTsẽ hoạt động chậm như nhau.

Khả năng duy nhất tôi có thể nghĩ đến là: Bạn nói rằng bảng được truy cập nhiều. Có thể người khác đã thực hiện một giao dịch rất dài (liên quan trực tiếp hoặc gián tiếp đến các hàng cụ thể đó) trong khi bạn đang cố gắng thực hiện DELETE.

Tôi nghĩ có lẽ bạn nên chèn một số hàng giả ở đó và cố gắng xóa chúng. Làm điều đó 2 hoặc 3 lần. Nếu có sự khác biệt lớn về thời lượng của DELETE, thì tải DB có lẽ là lý do.

Tái bút: Chỉ làm điều đó nếu mọi người sẽ không bị làm phiền bởi những hàng giả đó: D.


2
Vì vậy, câu trả lời của bạn là "Tôi không biết tại sao"?
Pacerier
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.