今天在写一个Query时,突然想到这个问题。看下面的一条例句:select * 
  from users_sysinfo u 
     , user_customfield uc
 where u.users_sys_id = uc.users_sys_id (+)
   and uc.users_sys_id is not null 
,其中users_sysinfo有100条记录,user_customfield有10条记录,两张表的主键都是users_sys_id,并且user_customfield中的主键在users_sysinfo表中都存在。由此衍射出的问题是:Oracle是如何执行这条select语句呢?
1. 如果是先执行表连接后再执行过滤条件“uc.users_sys_id is not null”,那么最终的记录就是10条。
2. 如果是先执行过滤条件“uc.users_sys_id is not null”,再进行表连接,那么结果就是100条。
Oracle中是如何执行这类select语句的呢?是根据分析计划而定还是说肯定按照铁定的步骤先执行1(2),然后再执行2(1)?
如果是内连接的话又是如何执行?
坐等高手来解惑。

解决方案 »

  1.   

    补充一下,这里将uc.users_sys_id is not null 替换为uc.users_sys_id = 1.最终结果就可能存在不一样。不过我是觉得对于外连接,Oracle应当是先连接后过滤,只是不敢确定,希望高手能够帮忙。
      

  2.   

    先执行联接再执行uc.users_sys_id is not null的判断。 如查是内联接的话uc.users_sys_id is not null则不需要判断了。
      

  3.   

    先执行where后面的哪个条件,这个要看Oracle优化模式是CBO还是RBO的。
    如果没有收集表的统计信息,那就是RBO了,会自下而上执行where后面的条件,也就是先执行
    uc.users_sys_id is not null条件。如果收集了表的统计信息,Oracle就会选择CBO,这个
    时候Oracle会自己根据执行计划选择先执行哪个条件更优,就会先执行哪个条件,但是结果是唯一的
      

  4.   

    先执行u.users_sys_id = uc.users_sys_id (+)
    后执行and uc.users_sys_id is not null 该写法效率低些
    一般建议这么写:
    select * 
      from users_sysinfo u 
         , (SELECT * FROM user_customfield WHERE users_sys_id IS NOT NULL) uc
     where u.users_sys_id = uc.users_sys_id
      

  5.   


    where子句里面的and,or,not:
    1.a and b(顺序执行)
          (1)a,b同true则true,
          (2)a,b一false则false,
             [1]若a为false,就没有必要在进行后面的判断了,整个表达式必为false;
             [2]若a为true,则进行后面的判断,b为true则表达式为true,若b为false,则整个表达式为false;
    2. a or b(顺序执行)
           (1)a,b一true则true
              [1]若a为true,就没必要在进行判断了,表达式为true;
              [2]若a为false,继续判断b,若b为false,表达式为false;若b为true,则表达式为true;
           (2)a,b同false则表达式返回false
              此情况下,a为false,然后b也为false;
    3.not a(先执行a,再取反)
          取反
          a->true, not a->false;
          a->false, not a->true;
      

  6.   

    1 where语句的执行顺序不会影响最终检索结果,只可能影响效率
    2 我也觉得左外连接加上右式不为空就等于内连接了不知道理解有没有错
      

  7.   

    如果CBO优化器有足够的统计信息肯定是先过滤再连接,RBO优化器就不好说了
      

  8.   

    select * 
      from users_sysinfo u 
         , user_customfield uc
     where u.users_sys_id = uc.users_sys_id (+)
       and uc.users_sys_id is not null这种写法就相当于内联,要想全部外联得加(+):
    and uc.users_sys_id(+) is not null内核执行顺序研究中
      

  9.   

    或许是我的问题描述的不够清楚,我想问的是:Oracle是先执行表连接然后再执行where条件里的过滤条件吗?我再表述一下:现有表A: aID aName        表B:  bID  bName
             1    a1                1     b1
             2    a2                2     b2
             3    a3
    Sql查询语句为:select * from A a, B b
                   where a.aID = b.bID (+)
                     and b.bID = 1若Oracle先执行表连接再执行过滤条件,那么最终结果将只有1条记录;若Oracle先执行过滤条件,再执行表连接,那么结果将是3条记录。若Oracle是根据CBO或者RBO来选择执行的话,那同一条sql语句岂不是会返回不同的数据?还是说不管什么情况,Oracle都会先执行外连接然后再执行过滤条件?
      

  10.   

    --查看执行计划, 自己分析
    explain plan for 执行的SQL
    select * from table(dbms_xplan.display())
      

  11.   

       两张表的主键都是users_sys_id ??
           那 uc.users_sys_id is not null 怎么可能有效果呢?