a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 427|回复: 2

[考试辅导] Oracle认证辅导:SQL条件的顺序对性能的影响

[复制链接]
发表于 2012-8-4 14:06:19 | 显示全部楼层 |阅读模式
经常有人问到oracle中的Where子句的条件书写顺序是否对SQL性能有影响,我的直觉是没有影响,因为如果这个顺序有影响,Oracle应该早就能够做到自动优化,但一直没有关于这方面的确凿证据。在网上查到的文章,一般认为在RBO优化器模式下无影响(10G开始,缺省为RBO优化器模式),而在CBO优化器模式下有影响,主要有两种观点:  a.能使结果最少的条件放在最右边,SQL执行是按从右到左进行结果集的筛选的;
4 K, x. p  X' G. k; }1 ~. _$ z) u  b.有人试验表明,能使结果最少的条件放在最左边,SQL性能更高。
# R! E* s8 s" n  查过oracle8到11G的在线文档,关于SQL优化相关章节,没有任何文档说过where子句中的条件对SQL性能有影响,到底哪种观点是对的,没有一种确切的结论,只好自己来做实验证明。结果表明,SQL条件的执行是从右到左的,但条件的顺序对SQL性能没有影响。
7 u4 C5 J6 ~, H5 Z5 i, c% l* F8 F  实验一:证明了SQL的语法分析是从右到左的
2 R! H. y  m0 i, I2 O9 A  下面的试验在9i和10G都可以得到相同的结果: 第1条语句执行不会出错,第2条语句会提示除数不能为零。: T4 f) t5 U0 q8 C& n
  1.Select 'ok' From Dual Where 1 / 0 = 1 And 1 = 2;5 x4 J. f% }/ l' g/ f+ E
  2.Select 'ok' From Dual Where 1 = 2 And 1 / 0 = 1;2 d' c6 _* ~+ _% I
  证明了SQL的语法分析是从右到左的。
5 g8 d. \, {) D5 P. e5 G1 k  实验二:证明了SQL条件的执行是从右到左的) K  x4 U# x% e- q% a/ q  o
  drop table temp;
& o8 z8 `& |( [: t9 y  create table temp( t1 varchar2(10),t2 varchar2(10));; Q: ]5 ~* ~( U! H) c7 R7 K+ e
  insert into temp values('zm','abcde');; [  t5 h5 Z- D" f" D8 J" _0 H
  insert into temp values('sz','1');
2 o* K' |! H8 j- a  insert into temp values('sz','2');
; k$ e8 Z" @4 V! o  commit;
/ s1 P$ s2 n) e  f  1. select * from temp where to_number(t2)>1 and t1='sz';2 u0 ?; t* [5 m- K
  2. select * from temp where t1='sz' and to_number(t2)>1;
0 _" q2 X( U% m2 o9 {  在9i上执行, 第1条语句执行不会出错,第2条语句会提示“无效的数字”$ z. l: K  K$ u  i
  在10G上执行,两条语句都不会出错。
% `, R9 t. ]0 x2 W  说明:9i上,SQL条件的执行确实是从右到左的,但是10G做了什么调整呢?5 Y) r. ]5 z* Y2 k& C! u
  实验三:证明了在10g上SQL条件的执行是从右到左的. O1 r, y; c. w; J
  Create Or Replace Function F1(v_In Varchar2) Return Varchar2 Is
( E3 X: G% k4 h2 w0 [: q' N: o' ~  Begin0 m6 U7 h; L) F, L: h" [
  Dbms_Output.Put_Line('exec F1');
( r, ^' G* ^+ w5 I! |  f  Return v_In;+ S  k3 }9 P! _2 E! O  _
  End F1;( I5 C/ l0 I6 s5 u& g7 c
  /
0 l/ _( ^: _. N* d9 u  Create Or Replace Function F2(v_In Varchar2) Return Varchar2 Is; _. z2 Q4 }) P
  Begin
. G! r9 V" M2 K) z1 g' o( ^2 k0 a- f  Dbms_Output.Put_Line('exec F2');
* e+ O% U# K8 n4 U- }9 D: \  Return v_In;1 l  q9 N* ]- a! }6 i6 b
  End F2;; M4 l% ?2 U5 g5 n( \, v. \
  /
回复

使用道具 举报

 楼主| 发表于 2012-8-4 14:06:20 | 显示全部楼层

Oracle认证辅导:SQL条件的顺序对性能的影响

 SQL> set serverout on;  SQL> select 1 from dual where f1('1')='1' and f2('1')='1';* h8 |' r1 g2 u& I0 R* `6 d1 _
  1
# S2 w2 l6 |0 B  g. s# O  A3 Z  ----------
) B5 i; p( c! p9 P  1% s3 S7 H# }7 E, i6 j
  exec F2
- Y6 ^6 g2 F0 M, ?; X; G( ^  exec F19 s) R# v6 V/ A* W$ I
  SQL> select 1 from dual where f2('1')='1' and f1('1')='1';$ S- R6 J" w3 S( A$ m6 ^
  13 m) j+ @% N2 ?# b
  ----------
- o# H% }( Y* n# @  1
) O3 o5 v; i9 h) }- A+ ~5 `: G  exec F1* J- {/ Q. i- F% L% m& B+ ?
  exec F29 J4 g3 P5 S; F1 o) Y0 x; [
  结果表明,SQL条件的执行顺序是从右到左的。) s+ Y8 g. a$ c+ ~. v
  那么,根据这个结果来分析,把能使结果最少的条件放在最右边,是否会减少其它条件执行时所用的记录数量,从而提高性能呢?
3 v* e" E- S. z; ~/ Y& ~# ]! z  例如:下面的SQL条件,是否应该调整SQL条件的顺序呢?: T, @/ i6 N9 k3 K; A
  Where A.结帐id Is Not Null
- ~, z) A; j: ~  ^. Y  And A.记录状态0
5 c: k+ n2 ]9 U) f; ?. K  And A.记帐费用=1
  Z. C8 ]; }4 |" R4 d' I# p0 O  And (Nvl(A.实收金额, 0)Nvl(A.结帐金额, 0) Or Nvl(A.结帐金额, 0)=0)
  _, q" Y3 j2 \4 M$ q2 ^" Z% u  And A.病人ID=[1] And Instr([2],','||Nvl(A.主页ID,0)||',')>02 w: H- p$ M" K4 m* V( K7 f. H
  And A.登记时间Between [3] And [4]
$ P$ Z! M4 L1 |4 Z& P7 v  And A.门诊标志1
* |# F* S; {  \$ P  实际上,从这条SQL语句的执行计划来分析,Oracle首先会找出条件中使用索引或表间连接的条件,以此来过滤数据集,然后对这些结果数据块所涉及的记录逐一检查是否符合所有条件,所以条件顺序对性能几乎没有影响。( I4 g% C# N; W+ ?" X5 u
  如果没有索引和表间连接的情况,条件的顺序是否对性能有影响呢?再来看一个实验。
8 ]7 ~. P: `# G2 o$ W6 i  实验四:证明了条件的顺序对性能没有影响。, f6 u0 W4 A$ i) t
  SQL> select count(*) from诊疗项目目录where操作类型='1';
3 B8 r- L; k. p- [6 ~  COUNT(*)+ I4 T- k6 G7 x
  ----------
# z% }* C# l) e  3251' Q  O9 J' A, @; F9 O& d
  SQL> select count(*) from诊疗项目目录where类别='Z';
5 R8 ?2 U, |& W7 w/ y  COUNT(*)
9 O) u: \' ]' ]$ u* S$ }  ----------
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-4 14:06:21 | 显示全部楼层

Oracle认证辅导:SQL条件的顺序对性能的影响

170  SQL> select count(*) from诊疗项目目录where类别='Z' and操作类型='1';5 y0 ~6 ]8 c6 a3 E3 f8 y) }2 R
  COUNT(*)
/ l+ {1 n7 k% e2 w' B# k* T8 Y  ----------
5 \# ^8 ]2 K& H  u* R; g4 _  o  1# U* I% F) m& r6 P$ Y/ S9 P1 u
  Declare
3 [/ V# l* X% A% {9 ?  V1 Varchar2(20);
( u  S* k6 u* n) r6 r) l, j  Begin) d, [. \' N# b7 C
  For I In 1 .. 1000 Loop
/ a" v& G9 |1 z1 E# @% X- e$ g* R  U  --Select名称Into V1 From诊疗项目目录Where类别= 'Z' And操作类型= '1';
# p) {. h& ?$ I2 U  select名称Into V1 from诊疗项目目录where操作类型='1' and类别='Z';
, V# b# n3 m/ W/ n  End Loop;
: d+ p; u9 O2 U# p3 r' A  End;
- c- I2 G+ s8 z+ G$ M, n4 c3 D  /( w# y2 s) x  p2 H/ e1 k
  上面的SQL按两种方式分别执行了1000次查询,结果如下:+ e0 T7 W) e2 o. O+ u8 |: c: B
  操作类型= '1'在最右|类别='Z'在最右
+ t0 E$ K' y/ l1 T% d5 E( Q# S( W  0.093                          |    1.014+ o6 P0 _( w3 K* _4 ^: }
  1.06                            |    0.999: k" o. d8 B6 L' _# \
  0.998                          |    1.014
7 N* Q: f3 j) l2 A3 p  按理说,从右到左的顺序执行,“类别='Z'”在最右边时,先过滤得到170条记录,再从中找符合“操作类型 = '1'”的,比较而言,“操作类型 = '1'”在最右边时,先过滤得到3251条记录,再从中找符合“类别='Z'”,效率应该要低些,而实际结果却是两者所共的时间差不多。
6 c% s+ N$ W% T/ i7 t3 \  其实,从Oracle的数据访问原理来分析,两种顺序的写法,执行计划都是一样的,都是全表扫描,都要依次访问该表的所有数据块,对每一个数据块中的行,逐一检查是否同时符合两个条件。所以,就不存在先过滤出多少条数据的问题。
& y& o7 u& u2 v% F& \  综上所述,Where子句中条件的顺序对性能没有影响(不管是CBO还是RBO优化器模式),注意,额外说一下,这里只是说条件的顺序,不包含表的顺序。在RBO优化器模式下,表应按结果记录数从大到小的顺序从左到右来排列,因为表间连接时,最右边的表会被放到嵌套循环的最外层。最外层的循环次数越少,效率越高。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-6-21 13:36 , Processed in 0.220427 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表