Oracle大in慢查询优化

1、某客户业务模块大in导致慢SQL:

2.从现场获取到慢SQL信息:

1)表数据量不大,只有几十万

2)表更新较为频繁,从另外系统同步过来,实际上变更并不频繁,只有少量的updates

3.AWR报告无明显异常:

4.业务逻辑分析:

1)原始SQL:

SELECT A.FId "id", A.fnumber "number", A.fctrlstrategy "ctrlStrategy", A.fmasterid "masterid", A.fstatus "status", A.fcreateorgid "createOrg.id"FROM xx_Material A WHERE A.FId IN (SELECT COLUMN_VALUE FROM UDT_INTTABLE(?)) AND (A.fbitindex IN (SELECT COLUMN_VALUE FROM UDT_INTTABLE(?)) OR (A.fcreateorgid = ? AND A.fctrlstrategy = ? OR A.fstatus = ? AND A.fctrlstrategy = ?) OR A.fctrlstrategy = ? AND (A.fcreateorgid = ? OR A.fstatus = ? AND A.fcreateorgid=100000))


2)SQL分析

UDT_INTTABLE是一个自定义类型,用于封装大in,规避Oracle in超过1000报错问题,涉及代码:

        CREATE OR REPLACE TYPE "UDT_INTTABLE" AS TABLE OF number(19)

使用IN (SELECT COLUMN_VALUE FROM UDT_INTTABLE(?)) 将大量in封装后,整个执行计划为FTS(未截图)


5.执行计划分析:

由于FID是主键,整个表几十W记录,而in只有上千个,从COST成本预估分析,正确的执行计划应该使用in..list(iterator) NL ,类似如下:

optimizer预计计算有误,执行计划FTS有问题


5.优化方案:

1)考虑使用table函数代替子查询( SELECT COLUMN_VALUE FROM UDT_INTTABLE(?))改写,如:

select * from t_big where id in (select * from table(UDT_INTTABLE(1,2,3,4,5,6,7,8,9,10,100))),执行计划如上。


2)将in转换为临时表(依赖程序框架实现),in list iterator转换为NL JOIN




请使用浏览器的分享功能分享到微信等