1 业务场景
客户需要一个报表统计工单的各种信息,于是我们利用公司报表平台做了一个报表导出功能。可是当我们准备上ver环境时测试反应报表导出虽然数据正确但性能不能达标,导出非常缓慢。于是我就开始分析报表sql。
2 问题分析
相信有过开发经验的同学都知道,讲到分析sql立马会想到explain。于是我用explain分析了下sql结果如下
大多数人看到这里发现key这列已经使用索引并且ref为const了就觉得都是用是索引了那sql好像没啥好优化的,这时候就开始分析能不能业务逻辑或开发逻辑上进行优化。
但是我们仔细看下26到33行rows这列你会发现虽然使用了索引但是这索引效率好像不大行,因为影响的行数都特别多。说明虽然使用了索引但是索引效率不太行啊。
为啥索引效率不行呢?我们看下key这行他们使用的索引是 lcs_advice_trace_operate_type_IDX,我们去表看表发现lcs_advice_trace_operate_type_IDX是通过operate_type表字段建立的,实际上operate_type字段在表了只有5种情况,这个索引完全没有区分度。
我们再来看看possible_keys这一列,发现其实有两个索引lcs_advice_trace_advice_no_IDX 和lcs_advice_trace_operate_type_IDX可以使用,而且分析表发现lcs_advice_trace_advice_no_IDX是一个非常有区分度的索引,因为lcs_advice_trace_advice_no_IDX是根据字段advice_no建立的,而advice_no在表中是一个唯一字段。
分析到这里我们应该知道问题就是,mysql选择了一个没有区分度的索引,导致查询缓慢
3 解决办法
既然是mysql选择了没有区分度的索引导致查询缓慢,那我们让mysql选择有区分度的索引就解决问题了,要改变mysql的执行计划有两个方法
方法一:使用FORCE INDEX指定mysql使用哪个索引
方法二:删除区分度不高的索引,显然索引lcs_advice_trace_operate_type_IDX完全没有区分度完全可以把它删除,让mysql只能选择索引lcs_advice_trace_advice_no_IDX。本例中我们删除lcs_advice_trace_operate_type_IDX后查询缓慢问题马上解决了
4 总结
- 我们要建立有效索引,对区分度不大的字段没必要建索引
- 我们要放让mysql走更有效的索引