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