Mysql 5.6 执行计划错误案例分析
Updated:
Understanding the Query Execution Plan
前提
Mysql 优化器本就是为了优化SQL语句的查找路径而存在,当优化器足够智能的时候,这是一件美事。但是,如果优化器犯二的时候呢?有的时候执行计划看上去非常好,但是慢的无可救药。有的时候执行计划看上去很差,却跑的很欢。 接下来我们一起来看一下下面的例子:
- 表结构
|
|
- total rows
|
|
- index
|
|
问题1
- SQL 1
|
|
- SQL 2
|
|
- 总结
- 为什么explain中的rows不一样,最终的扫描的Handler_read_prev一样呢?
哈哈,只能说explain 中的limit 欺骗了你。。。 limit optimization
问题二
针对以上案例,为什么Mysql 会选择brokerid 作为索引呢?为什么不用其他的索引呢?我们来强制指定看看
|
|
看样子,还是不行? 强制索引无效。。。怎么办?那我们就应该去看看Mysql到底是如何一步一步选择执行计划的,还好Mysql 5.6 提供了另外一种追踪途径 optimizer_trace
|
|
大家可以很清晰的看到,Mysql在之前还是有很多可以选择的索引,但是最后
reconsidering_access_paths_for_index_ordering 中却选择了brokerid,访问路径为index_scan.
奇了个怪了,为啥?google了一把后,发现之前有类似的bug Bug #70245,里面说eq_range_index_dive_limit 会影响range查询计划,官方文档确实也是这
么说的。But,无论我怎么设置eq_range_index_dive_limit的值,丝毫不会影响执行计划
|
|
那怎么办呢?
- 首先
既然brokerid干扰其优化器的选择,如果我将其drop掉,优化器是否能够选择正确的索引呢?
|
|
果然,Mysql选择了正确的索引,跑起来还不错。但是那个索引要经常被用到,不能被删除,结果这条道路是走不通的。
- 其次
再回头看看trace的选择,里面有关于”clause”: “GROUP BY”? 我就再想,是不是由于Group by的原因呢?不清楚,那就试试呗,于是将distinct去掉,试试看
|
|
情况貌似好转了,但是这样子是不满足业务逻辑的呀。。。。
于是,再仔细看看SQL语句的,发现order by 和 group by 重合了,,,为啥不利用group by来排序呢?
so,SQL语句这样修改一下
|
|
- 从性能上看
|
|
总结
- distinct,orderby ,group by,limit 这几个条件放在一起,会给Mysql 优化器带来很大的负担,建议尽量不要这样使用。