提高ORACLE速度三个注意事项

Author: 黑龙江 胡忠 Date: 1995-04-28

        1.FROM语句中表的顺序
        ORACLE的FROM语句处理表的顺序同我们通常认为的不同,它是按照从右向左的顺序处理FROM后所跟的多个表。
        2.WHERE语句中域的顺序
        WHERE语句是按照从左向右的顺序处理WHERE后所跟的各个域,依照这条规则,我们可以把能排除记录数最多的条件放在最左。
        我们知道了这两点,就可以选择合适的顺序,把可能排除较多记录的表和条件分别放在FROM和WHERE的最右和最左以尽可能多地逐级减少记录数。其实质就是尽可能首先生成满足条件记录数最少的中间表,从而达到减少磁盘I/O的目的。
        3.语句的简洁与速度的冲突
        一般编程人员愿意写非常简洁的程序来实现非常复杂的功能,在SQL语句中这样做往往得不偿失。由于SQL语句存在大量集合操作,分步求解反而会因大大减少磁盘I/O操作而极大提高求解速度。实际应用时要非常注意这一点。
        示例:
        结合前述三点,我们看看下面的例子:
        INSERT INTO crkbb
        SELECT a.年,a.月,b.物资代码,
        sum(nvl(a.收入数量,0)),sum(nvl(a.发出数量,0)),
        sum(nvl(a.计划金额,0)),sum(nvl(a.发出金额,0))
        FROM crk a,wzdmk b
        where b.物资代码=substr(a.物资代码,1,2*b.级别) and
        a.年='1994' and a.月='08'
        设计者本意是通过这一条语句求出94年08月各类物资的小计、合计、大类计,但该语句实际运行中有很多的冗余运算,带来大量不必要的磁盘I/O操作。我们分别剖析如下:
        (1)crk是库房日常出入库的流水帐基表,wzdmk是54大类物资代码表,求和主要是根据wzdmk中的物资代码到crk中作sum运算,必须先处理wzdmk,FROM语句顺序是正确的。
        (2)WHERE中条件始终是对有大量数据的CRK进行操作,不仅重复处理许多无用数据,而且条件中变量的引用也增加磁盘I/O次数,应按照汇总级别分步处理。
        改后SQL语句写成如下:
        INSERT INTO crkbb
        SELECT a.年, a.月, b.物资代码,
        sum(nvl(a.收入数量,0)),sum(nvl(a.发出数量,0)),
        sum(nvl(a.计划金额,0)),sum(nvl(a.发出金额,0))
        FROM crk a,wzdmk b
        where b.级别=5 and b.物资代码=substr(a.物资代码,1,10)
        and a.月='08' and a.年='1994'
        块①
        INSERT INTO crkbb
        SELECT a.年, a.月, b.物资代码,
        sum(nvl(a.收入数量,0)),sum(nvl(a.发出数量,0)),
        sum(nvl(a.计划金额,0)),sum(nvl(a.发出金额,0))
        FROM crkbb a,wzdmk b
        where b.级别=3 and b.物资代码=substr(a.物资代码,1,6)
        and a.月='08' and a.年='1994'
        块②
        INSERT INTO crkbb
        SELECT a.年,a.月,b.物资代码,
        sum(nvl(a.收入数量,0)),sum(nvl(a.发出数量,0)),
        sum(nvl(a.计划金额,0)),sum(nvl(a.发出金额,0))
        FROM crkbb a,wzdmk b
        where b.级别=2 and b.物资代码=substr(a.物资代码,1,4)
        and a.月='08' and a.年='1994'
        块③
        INSERT INTO crkbb
        SELECT a.年,a.月,b.物资代码,
        sum(nvl(a.收入数量,0)),sum(nvl(a.发出数量,0)),
        sum(nvl(a.计划金额,0)),sum(nvl(a.发出金额,0))
        FROM crk a,wzdmk b
        where b.级别=1 and b.物资代码=substr(a.物资代码,1,2)
        and a.月='08' and a.年='1994'
        块④
        改完以后,经块①处理生成的crkbb中记录数远比crk中的要少的多,实际工作中由1万8千条降为1千4百条,以后块②、块③、块④均只对有1千多条记录的crkbb进行处理,而这1千条记录服务器完全可以一次性读入内存,在内存里处理,速度自然大大提高。
        (黑龙江 胡忠)