到底有多严重, 请看下面的测试结果:
(这个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.