一次生产慢查询优化实例
背景:项目上线后,发现某查询接口比较慢,定位到是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,虽然还是不算快,但是已经算解决了问题啦。