一次生产慢查询优化实例
背景:项目上线后,发现某查询接口比较慢,定位到是SQL查询问题,查询时间大约在3~5s
。数据库是Oracle
。
1 | --待优化SQL |
XXX_XXX_STRATEGY
表的索引情况:
唯一索引:STRATEGY_ID
普通索引:CIF_NO,START_TIME,DIRECTION,END_TIME,T_TYPE
定位原因:
OR
前半段查询条件相对比较精确,查询结果是比较少的。
OR
后半段的 T_TYPE ='B'
在生产上查出了大量数据(万级),但是在后续业务处理时大部分被去重了(剩余数据为 百级)。
这里同事给出方案一:分表:将TYPE = 'B'
的数据存放在一个新建的表中,但这样问题是不管放在哪总是查询出了大量数据,总是快不了的。由于数据量大肯定走了全表扫描,使用索引也是无效的。
所以要将优化重点放到SQL
本身上。
首先肯定需要拆成两个SQL
,首先将OR
优化为 UNION ALL
试试情况:查询时间还是跟之前一样。
这时,我们看到这里的查询结果其实都被之后的去重逻辑给去掉了,我们能不能在查询的时候就给他去重呢?
答案是肯定的。
1 | --拆分出来的SQL |
根据业务逻辑,类型为'B'
的数据主要使用到的字段是FINANCE
,生产中推送入库时推送了大量的该字段的重复数据进来。这一点在UAT
环境中是没有预料到的。我们立马就想到了用分组来过滤,但是需要将FINANCE
字段相同的数据取最新的一条,这样分组同时还需要排序。先看最后优化的SQL
。
1 | SELECT |
我们主要使用了over()
函数:它给 partition by
的分组结果给提供了一个封闭的区间,而row_number()
函数:会在over()
的每个区间范围内重新分配一个递增的行号。这里我们取行号为1
的数据即是取按时间排序第一位的数据。
SQL
去重后在十万级的数据量下查询速度约为0.4s
,虽然还是不算快,但是已经算解决了问题啦。