mysql 优化器本就是为了优化sql语句的查找路径而存在,当优化器足够智能的时候,这是一件美事。但是,如果优化器犯二的时候呢?有的时候执行计划看上去非常好,但是慢的无可救药。有的时候执行计划看上去很差,却跑的很欢。 接下来我们一起来看一下下面的例子:
表结构
total rows
index
sql 1
sql 2
总结
为什么explain中的rows不一样,最终的扫描的handler_read_prev一样呢?
针对以上案例,为什么mysql 会选择brokerid 作为索引呢?为什么不用其他的索引呢?我们来强制指定看看
看样子,还是不行? 强制索引无效。。。怎么办?那我们就应该去看看mysql到底是如何一步一步选择执行计划的,还好mysql 5.6 提供了另外一种追踪途径 optimizer_trace
大家可以很清晰的看到,mysql在之前还是有很多可以选择的索引,但是最后
reconsidering_access_paths_for_index_ordering 中却选择了brokerid,访问路径为index_scan.
bug.php?id=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 优化器带来很大的负担,建议尽量不要这样使用。