zoukankan      html  css  js  c++  java
  • SQL where 条件顺序对性能的影响有哪些

    经常有人问到oracle中的Where子句的条件书写顺序是否对SQL性能有影响,我的直觉是没有影响,因为如果这个顺序有影响,Oracle应该早就能够做到自动优化,但一直没有关于这方面的确凿证据。在网上查到的文章,一般认为在RBO优化器模式下无影响(10G开始,缺省为RBO优化器模式),而在CBO优化器模式下有影响,主要有两种观点:

      a.能使结果最少的条件放在最右边,SQL执行是按从右到左进行结果集的筛选的;

      b.有人试验表明,能使结果最少的条件放在最左边,SQL性能更高。

      查过oracle8到11G的在线文档,关于SQL优化相关章节,没有任何文档说过where子句中的条件对SQL性能有影响,到底哪种观点是对的,没有一种确切的结论,只好自己来做实验证明。结果表明,SQL条件的执行是从右到左的,但条件的顺序对SQL性能没有影响。

      实验一:证明了SQL的语法分析是从右到左的

      下面的试验在9i和10G都可以得到相同的结果: 第1条语句执行不会出错,第2条语句会提示除数不能为零。

      1.Select 'ok' From Dual Where 1 / 0 = 1 And 1 = 2;

      2.Select 'ok' From Dual Where 1 = 2 And 1 / 0 = 1;

      证明了SQL的语法分析是从右到左的。

      实验二:证明了SQL条件的执行是从右到左的

    drop table temp;
    create table temp( t1 varchar2(10),t2 varchar2(10));
    insert into temp values('zm','abcde');
    insert into temp values('sz','1');
    insert into temp values('sz','2');
    commit;

    1. select * from temp where to_number(t2)>1 and t1='sz';
    2. select * from temp where t1='sz' and to_number(t2)>1;

      在9i上执行, 第1条语句执行不会出错,第2条语句会提示“无效的数字”

      在10G上执行,两条语句都不会出错。

      说明:9i上,SQL条件的执行确实是从右到左的,但是10G做了什么调整呢?

      实验三:证明了在10g上SQL条件的执行是从右到左的

    Create Or Replace Function F1(v_In Varchar2) Return Varchar2 Is
    Begin
    Dbms_Output.Put_Line('exec F1');
    Return v_In;
    End F1;
    /
    Create Or Replace Function F2(v_In Varchar2) Return Varchar2 Is
    Begin
    Dbms_Output.Put_Line('exec F2');
    Return v_In;
    End F2;
    /
    SQL> set serverout on;
    SQL> select 1 from dual where f1('1')='1' and f2('1')='1';
    1
    ----------
    1
    exec F2
    exec F1
    SQL> select 1 from dual where f2('1')='1' and f1('1')='1';
    1
    ----------
    1
    exec F1
    exec F2

      结果表明,SQL条件的执行顺序是从右到左的。

      那么,根据这个结果来分析,把能使结果最少的条件放在最右边,是否会减少其它条件执行时所用的记录数量,从而提高性能呢?

      例如:下面的SQL条件,是否应该调整SQL条件的顺序呢?

    Where A.结帐id Is Not Null
    And A.记录状态<>0
    And A.记帐费用=1
    And (Nvl(A.实收金额, 0)<>Nvl(A.结帐金额, 0) Or Nvl(A.结帐金额, 0)=0)
    And A.病人ID=[1] And Instr([2],','||Nvl(A.主页ID,0)||',')>0
    And A.登记时间Between [3] And [4]
    And A.门诊标志<>1

      实际上,从这条SQL语句的执行计划来分析,Oracle首先会找出条件中使用索引或表间连接的条件,以此来过滤数据集,然后对这些结果数据块所涉及的记录逐一检查是否符合所有条件,所以条件顺序对性能几乎没有影响。
            如果没有索引和表间连接的情况,条件的顺序是否对性能有影响呢?再来看一个实验。

      实验四:证明了条件的顺序对性能没有影响。

    SQL> select count(*) from诊疗项目目录where操作类型='1';
    COUNT(*)
    ----------
    3251
    SQL> select count(*) from诊疗项目目录where类别='Z';
    COUNT(*)
    ----------
    170
    SQL> select count(*) from诊疗项目目录where类别='Z' and操作类型='1';
    COUNT(*)
    ----------
    1
    Declare
    V1 Varchar2(20);
    Begin
    For I In 1 .. 1000 Loop
    --Select名称Into V1 From诊疗项目目录Where类别= 'Z' And操作类型= '1';
    select名称Into V1 from诊疗项目目录where操作类型='1' and类别='Z';
    End Loop;
    End;
    /

      上面的SQL按两种方式分别执行了1000次查询,结果如下:

      操作类型= '1'在最右|类别='Z'在最右

      0.093                            |      1.014

      1.06                              |      0.999

      0.998                            |      1.014

      按理说,从右到左的顺序执行,“类别='Z'”在最右边时,先过滤得到170条记录,再从中找符合“操作类型 = '1'”的,比较而言,“操作类型 = '1'”在最右边时,先过滤得到3251条记录,再从中找符合“类别='Z'”,效率应该要低些,而实际结果却是两者所共的时间差不多。

      其实,从Oracle的数据访问原理来分析,两种顺序的写法,执行计划都是一样的,都是全表扫描,都要依次访问该表的所有数据块,对每一个数据块中的行,逐一检查是否同时符合两个条件。所以,就不存在先过滤出多少条数据的问题。

      综上所述,Where子句中条件的顺序对性能没有影响(不管是CBO还是RBO优化器模式),注意,额外说一下,这里只是说条件的顺序,不包含表的顺序。在RBO优化器模式下,表应按结果记录数从大到小的顺序从左到右来排列,因为表间连接时,最右边的表会被放到嵌套循环的最外层。最外层的循环次数越少,效率越高。

  • 相关阅读:
    Overloaded的方法是否可以改变返回值的类型
    parseXXX的用法
    java的类型转换问题。int a = 123456;short b = (short)a;System.out.println(b);为什么结果是-7616?
    UVA 10405 Longest Common Subsequence(简单DP)
    POJ 1001 Exponentiation(大数处理)
    POJ 2318 TOYS(计算几何)(二分)
    POJ 1265 Area (计算几何)(Pick定理)
    POJ 3371 Flesch Reading Ease (模拟题)
    POJ 3687 Labeling Balls(拓扑序列)
    POJ 1094 Sorting It All Out(拓扑序列)
  • 原文地址:https://www.cnblogs.com/firstdream/p/7241268.html
Copyright © 2011-2022 走看看