记一次mysql like concat查询优化

1,975 阅读2分钟

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

题记

接到任务客户要开发一张报表才能搞验收,时间紧任务重。
了解了需求后开始马不停蹄的开始编写查询的sql了,然后劈里啪啦的敲代码了。
终于搞完了,丢给了现场去测试。
现场反馈数据展示可以了,取数也是对的,然后让客户看一眼。
客户一打开报表只见页面再那里转圈圈,然后客户喝了几口茶,慢慢的说到太太太慢了。
现场这时就反馈了这报表需要优化下。

需求

系统里面有科目表、预算执行表。。。例如预算上报等
科目表从名字就可以看出是存放的预算科目表,执行表放的是付款挂接的预算明细

报表的其他统计的先不说暂且先不关注,主要是执行数据的统计。

执行统计里面如果是上级科目需要汇总子科目的执行数,但执行表的数据都是明细。

撸代码

开始的做法

直接丢个子查询进去

(SELECT SUM(fp.PROCESS_CUR_MONEY)
                       FROM fbs_budget_process fp
                      WHERE fp.status = '95'
                        AND fp.process_date >= pm.begin_date
                        AND fp.process_date <= pm.END_DATE
                        AND fp.item_code LIKE CONCAT(pm.itemCode, '%')         
) processMoney

优化

经过一步一步拆分执行的sql,发现就是执行金额统计慢. 只用了三个字段分别是status、process_date、item_code 加索引吧(process_date、item_code)。

image.png

直接跑了下还是慢

来看下执行计划

image.png

一脸懵逼 索引只执行了日期process_date,没有科目item_code

在我得理解中科目关联我用了like abc% 应该走索引的

然后我试下,固定科目的时候索引出来了。难道动态匹配的时候索引会消失,有知道的老铁可以给我留言

image.png

中途试了下locate、POSITION (有效的)都没效果

如果是%jkjk 的可以用反转函数求解

没招了,最后发现in操作居然走索引,

修改前

(SELECT SUM(fp.PROCESS_CUR_MONEY)
                       FROM fbs_budget_process fp
                      WHERE fp.status = '95'
                        AND fp.process_date >= pm.begin_date
                        AND fp.process_date <= pm.END_DATE
                        AND fp.item_code LIKE CONCAT(pm.itemCode, '%')         
           )

修改后 试下了这下走索引了

(SELECT SUM(fp.PROCESS_CUR_MONEY)
       FROM fbs_budget_process fp
       WHERE 
       fp.item_code in (select fi.ITEM_CODE from fbs_item fi where fi.ITEM_CODE like CONCAT(pm.itemCode,'%') )
       AND fp.status = '95'
       AND fp.process_date BETWEEN pm.begin_date and pm.END_DATE)

回顾下最后

平时在网上看 like 匹配符在右边的时候是走索引的,但这个好像只能是固定的前缀
其实 like CONCAT(pm.itemCode,'%') 动态匹配的时候是不走索引的
     like CONCAT('200','%') 固定了就走索引了

转换:
有单一的 like concat转为in 和 小表的like concat

fp.item_code in (select fi.ITEM_CODE from fbs_item fi where fi.ITEM_CODE like CONCAT(pm.itemCode,'%') )
     
处理用了科目表(fbs_item)数据量小,
                                在匹配出子科目的时候执行速度快点,
                                然后主表in走索引