分类: Oracle DB |
百试不爽的替换:(Tuning小技巧中已添加~)
当Table只作为筛选条件使用时,可以用EXIST (SELECT 'x' FROM table_name WHERE
condition)替换整张表的串联;
当Table只抓一个栏位且不作为筛选条件的时候,使用SELECT中的子查询去替换整张表的串联,尤其是对于外联接的Table,百试不爽
超大超慢逻辑复杂的View:
前一阵子,一直停停走走的写一个View。
我的工作语言是SQL,我每天下SQL也没有呕吐,但是这次真的快吐了。
Oracle ERP中有这样一些模组:PO(Purchase Order),SO(Sale
Order),INV(Inventory),AR(Account Receive).不知道拼写有没有错误:)
这支View,用户要串到PO,SO,INV三个模组,并且使用了两个毁灭性的Table:一个是INV那边的料,料可是非常多的,每颗料一笔数据,有上万笔,它的索引又是组合索引,串起表来总是要串到非常细的表~~
另一个就是AR那边的,它的数据量真是海啊~~上百万得有了吧?我要把它们几乎全串进来,还要做聚和,还要按料去分组~~
为什么要取全部呢?因为用户要输入时间,在计算的时候,要根据用户输入的不同的时间段去计算各种和,足足七个求和,分别来自不同模组的不同时期……
这时我已经出了一篓的汗了~~我明知它会跑死,还是顶着寒意让它跑了,结果是,真的跑死了!
想象着各种解决办法:
Solution1
首先想到的是,先去跑一个Package,我会在Package中分别去抓各个模组求和的数据,然后分别放在一个个中转的Table里面,最后再由一个View来从这些个Table中抓取出数据,这办法好啊,将效能提高了很多啊!运行时间很合理啊~可是,用户不能接受!
第一:用户手动去跑一个Package?这不合理。用户不会付钱的。
那么好吧,那我把跑这个Package的工作交给我们的系统去做吧,每天定时去跑一下,用户不就不用去跑了吗?不行!用户还是不接受。
这就是第二:用户要获得即时的信息,如果他此刻更改了一笔数据,他要看到立即更改的结果,怎么可以看到12小时之前的数据??不行!
好吧,以上解决办法告败。
Solution2
接着,我尝试了PM建议并且跟User商定确认了的方法,将抓取时间缩减到近三个月。
三个月虽然数据大大减少,但是实际它对SQL语句的结构没有本质的影响,它的执行计划一样是很慢的,一样是非动态的,一样是跑死的~~这次虽然没有在细数据的抓取上跑死,可是到去生成报表的时候,是必死无疑,结果是,四个半小时后,跑出来零笔数据,这是不正确的。
Solution3
我问PM,能不能只抓当前月的?PM又跟我讨价还价,能不能抓前月,本月和下月的?
我问为什么要抓下月的?PM说,下月会有预下的定单呀~说的也是~
我忽然灵光一闪,这的确是个好办法,我一月一月的抓,再把三个月的作Union,Union完了之后加一个月份的字段,这样用户选择完了月份,另外的两个Union就没意义,这样也不会影响它的Performance。
好了,实现了,真的实现了,限定了时间的SQL语句结构是发生了本质的变化的。因为不用抓时间字段,可以将Sum放到Select中的子查询里,Oracle会自动将它转成动态SQL去运行(我猜的,但是是有依据的,从这点上,我越来越相信Oracle的智能比我强!)。动态地去运行省了多少时间啊~全部SUM完了之后,才用了一分钟多一些。这跟四个半小时是多大的差别啊!!
真是好东西!
顺便提一下,学到一个新东西,我师傅教的,就是抓当月时间的方法,Oracle提供的几个函数就可以办到:
SELECT LAST_DAY (ADD_MONTHS (SYSDATE, -1)) + 1 "当月第一天"
,LAST_DAY (SYSDATE) "当月最后一天"
FROM DUAL
FROM
好了,本文结束!