性能瓶颈在函数的乱用。原代码黄色部分。
12分钟->35秒
---------------------------------------------------------------------------------------------
1.对两个函数调用多次,而且两个函数之间还有调用关系。(优化器是可以自动把函数体拆出来,拼到主查询里面一起优化的。但是太复杂了它也蒙。)
IsSpecial和gettradedate函数都是从1010表拿数据。
IsSpecial 扫2次1010表
Gettradedate 扫1次1010表
而4603表有25万多数据,对这个查询用了2次IsSpecial 和3次 Gettradedate,最糟糕的情况对1010表的扫描次数大约25万*(2+3) =125万次
用with把1010逻辑提出来,然后通过cross join连接到主查询,只扫一次。
2.这个案例跟昨天那个代码结构相似,但是情况正好相反。
如果把or改成union,性能反而会变慢。(昨天的把or改成union性能会变快)
开始判断性能瓶颈的时候发生了点悲剧。4603表有25万的数据,唯一性索引在OB_OBJECT_ID上面(错看成在f1_4603上了,o(╯□╰)o),而我们需要的只有2500左右,而且与1090相连用的是f1_4603.
所以错认为了走4603的索引效率会变高。
其实这个案例,不管索引在OB_OBJECT_ID还是f1_4603上面都没有用。因为真正把数据从25万筛选成2500的条件是在f3_4603上面,而f3上面没有索引,所以必须全表扫描。
所以,如果把or改成了union,本来对4603表的全扫描只扫1次,就会变成2次,效率反而降低。(昨天的案例把or改为union,从1次全表扫描变为2次索引扫描,效率提升)。
3.其他相似子查询,可按之前的办法合并。
-------------------------------优化后代码----------------------------------------------
with td as
(select max(f1_1010) - min(f1_1010) special,
max(f1_1010) ed,
min(f1_1010) sd
from (select f1_1010
from wind.tb_object_1010
where f1_1010 < to_char(&PlanTime, 'yyyymmdd')
order by f1_1010 desc)
where rownum <= 2)
select *
from (Select case
when f16_1090 like '%!%' then
substr(f16_1090, 1, instr(f16_1090, '!') - 1)
else
F16_1090
end Zqdm,
case
when nvl(F6_4603, 0) = 0 then
nvl(F4_4603, 0)
else
nvl(F6_4603, 0)
end Net_value,
0 Begin_Net,
case
when nvl(f4_4603, 0) <> 0 then
nvl(nvl(F5_4603, f4_4603), 0)
when nvl(f4_4603, 0) = 0 then
nvl(F5_4603, 0)
end Total_net,
---除货币基金累计未公布时,取单位净值[20140507]