一、事件起因
最近一直在维护的一个项目,昨晚突然收到多个投诉,说接口反应慢,耗时较长。经排查代码,发现是sql查询中索引使用不当引发的慢查询问题导致的,现记录在此,希望大家可以引以为鉴。
二、代码分析
事件背景很简单,就是有一张数据总量有四百多万的订单表,单表sum查询某一字段的总和,条件是有四个条件,sql如下:
SELECT
sum( t.fee )
FROM
biz_parking_order t
WHERE
t.del_flag = '0'
AND t.STATUS = '1'
AND t.code = '37090303001'
AND t.type = '1';
此时sql耗时大约四五秒的样子,确实有点慢。
explain一下,发现能命中的单个索引,都能命中,说明也走了索引了。
这就奇怪了,继续往后面看,发现Extra中有这么一句提示:
Using intersect(idx_code,idx_del_status,idx_type); Using where。
intersect?啥意思,很少遇见过,没事儿,用翻译软件翻译一下,是交叉的意思。
这时,意思就很明白了,就是说使用到的索引有交叉的情况。那具体是如何解释的呢?经查阅资料发现:
Using Intersect是指会在查询时对使用到的索引执行同步扫描分别获取数据集,并对所获得的数据集取交集。
在上述的例子中,则是分别使用idx_code索引、idx_del_status索引、idx_type索引获取数据集,并对获取的数据集取交集。
这么说的话,问题的原因就很显而易见了,这样的实现是可能出现性能问题的,比如其中某个索引的效率不高时,或者当内存不足以容量数据集时,都可能会导致这种执行计划执行缓慢。Using Intersect不一定会比联合索引或者单列索引执行效率高。
三、解决办法
知道了原因之后,那就好解决了,既然单个索引会引起数据集交叉问题,那就不适用单个索引了,创建一个联合索引试试。说干就干,
create index idx_del_status_code_type on order(del_flag,STATUS,code,type); 执行,成功!
然后再explain一下,没问题,走了联合索引。
然后执行一下sql查询,
哇!速度快了好几十倍,简直六的飞起!!!
测试环境测一遍,没问题,上线,线上回归,没毛病。搞定!!!
四、总结
通过此次事件,我们可以发现,单个索引在使用过程中,有可能会出现的交叉问题以及使用联合索引可以解决这一问题的方法。所以在创建索引的时候,我们要根据具体业务场景和SQL语句来评判到底是使用单索引还是联合索引。