提高ORACLE速度三个注意事项 黑龙江 胡忠 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千条记录服务器完全可以一次性读入内存,在内存里处理,速度自然大大提高。 (黑龙江 胡忠)