1. 程式人生 > >當在mysql5.7上發現這個bug,小心臟不好受了

當在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.