MySQL数据库5.6 explain update一个疑似bug

5.6 的新增特性,允许对DML语句做explain。这下大家高兴了,碰到复杂更新语句(且还造成慢查询)要自己手动改成select语句的日子终于到头了。

饶有兴致的试用了一把,总体感觉不错,不过发现一个bug。

复现    

mysql> create table tb(id int primary key , c int);
Query OK, 0 rows affected (0.01 sec)mysql> insert into tb values(1,1);
Query OK, 1 row affected (0.00 sec)mysql> insert into tb values(2,2);
Query OK, 1 row affected (0.00 sec)mysql> explain select * from tb where id=1;
+—-+————-+——-+——-+—————+———+———+——-+——+——-+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+—-+————-+——-+——-+—————+———+———+——-+——+——-+
|  1 | SIMPLE      | tb    | const | PRIMARY       | PRIMARY | 4       | const |    1 | NULL |
+—-+————-+——-+——-+—————+———+———+——-+——+——-+
1 row in set (0.00 sec)

mysql> explain update tb   tb set c=2 where id=1;
+—-+————-+——-+——-+—————+———+———+——+——+————-+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+—-+————-+——-+——-+—————+———+———+——+——+————-+
|  1 | SIMPLE      | tb    | range | PRIMARY       | PRIMARY | 4       | NULL |    1 | Using where |
+—-+————-+——-+

 这里我们看到,在explain update的结果中,type=range,并且Extra是Using where。

这两个值的意思就是,MySQL做了一个range查询,即使只返回一行,也多做了一个next操作,而且Using where,表示从主键取出来的行还做了字段比较。

或者更直接一点,跟explain select的结果不一致。

分析

刚好趁机看一下explain dml的实现。发现explain update/deelte 不是沿用原来的逻辑,而是单独实现了一个Explain_table来处理。

在这个Explain_table的explain_join_tab逻辑(也就是获取返回结果的type字段的值)中,返回值里没有返回JT_CONST的选项,只有merge和range。

相同的,由于没有考虑const的情况,在得到Extra列的过程中,最少是Using Where

实际上,如果对于唯一键上的等值查找,是不需要做range查询,并且返回结果也不需要做值判断

实际执行流程

         Explain 多少是个锦上添花的动作,但是如果实际执行也是这么做,那就会影响性能(增加一次调用next和值比较),这就会对使用性能造成影响。

所幸的是,5.6.10在执行期间的逻辑还是正确的: 对于unique index的等值查询,只返回一行,在get_next()时有判断,直接返回HA_ERR_END_OF_FILE。
多表的explain update

mysql> explain update tb ,t1  set c=c+1,y=y+1 where tb.id=1 and t1.id=1;
+—-+————-+——-+——-+—————+———+———+——-+——+——-+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+—-+————-+——-+——-+—————+———+———+——-+——+——-+
|  1 | SIMPLE      | tb    | const | PRIMARY       | PRIMARY | 4       | const |    1 | NULL  |
|  1 | SIMPLE      | t1    | const | PRIMARY       | PRIMARY | 4       | const |    1 | NULL  |
+—-+————-+——-+——-+—————+———+———+——-+——+——-+

可以看到多表的explain update结果就是正确的,原因是单表的explain update/delete单独实现了Explain_table,而多表与explain select相同,走的是另外一个类Explain_join,这个过程的逻辑与以前版本(5.5-)是相同的。

有兴趣的同学可以一起探讨下这个patch

2 thoughts on “MySQL数据库5.6 explain update一个疑似bug

  1. update和select的优化流程有区别,没有const table的优化,只有quick select的优化,但是对于主键的update,如果WHERE条件中除了主键还包含其他条件,比如UPDATE T1 SET C2=10 WHERE ID = 1 AND C2 = 5,根据ID获取一行数据后,还会进行C2=5的条件判断,也就是所谓的Using Where,
    这样的话,是不是pathc中仅仅将EXTRA设为none有点不妥呢,但是根据是否包含cond将extra设置成Using where 又和 const table这种type有点歧义,但是又无法给出Impossible Where这样的判断。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>