當在mysql5.7上發現這個bug,小心臟不好受了
近期連續很長一段時間忙成狗, 沒有寫些文章來跟大家分享。現在接近晚上12點,但還是準備把這個bug簡單分享出來。發現這個bug已有半天,現在提起來,依然心有餘悸。因此將其儘早分享出來,希望各位mysql dba朋友儘量別踏入這個雷區。 到底有多嚴重, 請看下面的測試結果:
(這個bug的線索來源一個不曾相識的朋友,前段時間通過郵件向作者請教這個問題,因為太忙,沒有顧上,當時也不以為然。今天抽時間來複核這個問題,結果大吃一驚。非常感謝這個朋友)。
一個表,表結構如下:
CREATE TABLE “user_task” (
“id” int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT ‘自增ID’,
“parent_id” int(10) NOT NULL DEFAULT ‘0’ COMMENT ‘問題id’,
“author” int(10) NOT NULL DEFAULT ‘0’ COMMENT ‘釋出人pid’,
“con_id” int(10) NOT NULL COMMENT ‘群組id’,
“type” tinyint(2) NOT NULL DEFAULT ‘0’ COMMENT ‘型別(0 問題;1回答)’,
“title” varchar(200) NOT NULL DEFAULT ” COMMENT ‘標題’,
“info” varchar(500) NOT NULL DEFAULT ” COMMENT ‘文字’,
“pic” text NOT NULL COMMENT ‘圖片(json)’,
“audio” text NOT NULL COMMENT ‘音訊(json)’,
“start_time” int(10) NOT NULL DEFAULT ‘0’ COMMENT ‘釋出時間’,
“end_time” int(10) NOT NULL DEFAULT ‘0’ COMMENT ‘截止時間’,
“create_at” int(10) NOT NULL,
“modify_at” timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
“isread” tinyint(3) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘0 已讀 1 未讀’,
PRIMARY KEY (“id”),
UNIQUE KEY “idx_con_title” (“con_id”,”title”)
) ENGINE=InnoDB AUTO_INCREMENT=401 DEFAULT CHARSET=utf8
這個表一個主鍵+一個唯一性索引。資料量也很少。
mysql> select count(*) from user_task;
+———-+
| count(*) |
+———-+
| 54 |
+———-+
1 row in set (15.76 sec)
總共54條資料。
然後我們執行下面的這些sql , 請開始仔細觀察。
mysql> SELECT distinct con_id FROM user_task where id in (56,57);
+——–+
| con_id |
+——–+
| 844 |
+——–+
mysql> explain SELECT distinct con_id FROM user_task where id in (56,57);
+—-+————-+———–+————+——-+———————–+———+———+——+——+———-+——————————+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+—-+————-+———–+————+——-+———————–+———+———+——+——+———-+——————————+
| 1 | SIMPLE | user_task | NULL | range | PRIMARY,idx_con_title | PRIMARY | 4 | NULL | 2 | 100.00 | Using where; Using temporary |
+—-+————-+———–+————+——-+———————–+———+———+——+——+———-+——————————+
檢視執行計劃,走了主鍵索引。
mysql> SELECT distinct con_id FROM user_task where id in (56,57,58);
+——–+
| con_id |
+——–+
| 844 |
| 785 |
+——–+
2 rows in set (17.30 sec)
mysql> SELECT distinct con_id FROM user_task where id in (56,57,58,66);
+——–+
| con_id |
+——–+
| 844 |
| 785 |
+——–+
mysql> SELECT distinct con_id FROM user_task where id in (56,57,58,66,70);
+——–+
| con_id |
+——–+
| 844 |
| 785 |
+——–+
2 rows in set (20.64 sec)
mysql> SELECT distinct con_id FROM user_task where id in (56,57,58,66,70,71);
Empty set (3 min 0.16 sec)
看到了沒, 妖娥子在這裡出現了,where 條件範圍變大了, 結果卻沒有了,一身汗。。。。。
結果為什麼會變沒有了? 誰吃了這個結果? 檢視執行計劃,
mysql> explain SELECT distinct con_id FROM user_task where id in (56,57,58,66,70,71);
+—-+————-+———–+————+——-+———————–+—————+———+——+——+———-+—————————————+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+—-+————-+———–+————+——-+———————–+—————+———+——+——+———-+—————————————+
| 1 | SIMPLE | user_task | NULL | range | PRIMARY,idx_con_title | idx_con_title | 4 | NULL | 6 | 11.11 | Using where; Using index for group-by |
+—-+————-+———–+————+——-+———————–+—————+———+——+——+———-+—————————————+
1 row in set, 1 warning (0.00 sec)
發現走的是idx_con_title 索引 。
鄙視mysql: 走這個索引也無傷大雅, 幹嘛把結果弄丟了?
如果改寫成group by , 如下
SELECT con_id ,count(*) FROM user_task where id in (56,57,58,66,70,71) group by con_id ;
結果正常。
如果將索引idx_con_title 刪除, 下面sql結果正常。
SELECT distinct con_id FROM user_task where id in (56,57,58,66,70,71);
巨坑巨坑的bug,,,,,,且在5.7.18 以及5.7.20上均出現,其他版本未測試。
目前懷疑: 問題出現mysql的優化器上面,使用另外一個索引時,執行路徑不完整(錯誤)導致 。明天向官方提bug.