zoukankan      html  css  js  c++  java
  • Oracle外连接的执行计划中没有出现OUTER的例子

    Oracle外连接的执行计划中没有出现OUTER的例子

    前言

    以左连接为例子,主要是被CBO改为为内连接了。

    这里有人曾经也有这个疑问:一个奇怪的执行计划(为什么不是HASH JOIN OUTER 关联)

    环境构造

    create table a (id number,name varchar2(20));
    create table b (id number,name varchar2(20));
    insert into a values(1,'a');
    insert into a values(2,'b');
    insert into a values(3,null);
    insert into a values(4,'d');
    insert into a values(5,null);
    insert into a values(6,'a');
    insert into b values(1,'a');
    insert into b values(2,'b');
    insert into b values(3,'c');
    insert into b values(4,null);
    insert into b values(5,null);
    insert into b values(6,'a');
    commit;
    create index idx_a_id on a(id);
    create index idx_a_name on a(name);
    create index idx_b_id on b(id);
    create index idx_b_name on b(name);
    exec dbms_stats.gather_table_stats(ownname => 'ZKM',tabname => 'A',estimate_percent => 100,method_opt => 'FOR ALL COLUMNS SIZE REPEAT',degree => 1 ,no_invalidate => false); 
    exec dbms_stats.gather_table_stats(ownname => 'ZKM',tabname => 'B',estimate_percent => 100,method_opt => 'FOR ALL COLUMNS SIZE REPEAT',degree => 1 ,no_invalidate => false);

    现象

    比如SQL语句:

    select /*+ use_hash(a,b) */ a.*,b.* from a left join b on a.name=b.name where b.name='a';
    21:48:37 ZKM@qadb1(733)> select /*+ use_hash(a,b) */ a.*,b.* from a left join b on a.name=b.name where b.name='a';
    
     ID NAME  ID NAME
    --- ---- --- ----
      6 a      1 a
      1 a      1 a
      6 a      6 a
      1 a      6 a
    
    Elapsed: 00:00:00.02
    21:48:38 ZKM@qadb1(733)> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
    
    PLAN_TABLE_OUTPUT
    ---------------------------------------------------------------------------------------------------------------------------------------
    SQL_ID  8w2cmmcw2t2qc, child number 0
    -------------------------------------
    select /*+ use_hash(a,b) */ a.*,b.* from a left join b on a.name=b.name
    where b.name='a'
    
    Plan hash value: 1107873403
    
    --------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                    | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
    --------------------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT             |            |      1 |        |      4 |00:00:00.02 |       6 |       |       |          |
    |*  1 |  HASH JOIN                   |            |      1 |      2 |      4 |00:00:00.02 |       6 |  2061K|  2061K|  693K (0)|
    |   2 |   TABLE ACCESS BY INDEX ROWID| A          |      1 |      1 |      2 |00:00:00.01 |       2 |       |       |          |
    |*  3 |    INDEX RANGE SCAN          | IDX_A_NAME |      1 |      1 |      2 |00:00:00.01 |       1 |       |       |          |
    |   4 |   TABLE ACCESS BY INDEX ROWID| B          |      1 |      1 |      2 |00:00:00.01 |       4 |       |       |          |
    |*  5 |    INDEX RANGE SCAN          | IDX_B_NAME |      1 |      1 |      2 |00:00:00.01 |       2 |       |       |          |
    --------------------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - access("A"."NAME"="B"."NAME")
       3 - access("A"."NAME"='a')
       5 - access("B"."NAME"='a')
    
    
    25 rows selected.
    
    Elapsed: 00:00:00.04

     执行计划中的是HASH JOIN,而不是HASH JOIN OUTER。

    就是因为实际上SQL被CBO改写成

    select a.*,b.* from a , b where a.name=b.name and b.name='a';

    其他的例子

    select a.*,b.* from a left join b on a.name=b.name where b.name is not null;
    等价于
    select a.*,b.* from a,b where a.name=b.name;
    select a.*,b.* from a left join b on a.name=b.name where a.name='a';
    等价于,但还是左连接
    select a_new.*,b.* from (select * from a where a.name='a') a_new left join b on a_new.name=b.name;

    需要注意的是:

    select a.*,b.* from a left join b on a.name=b.name where b.name is null;
    不等价
    select a.*,b.* from a,b where a.name=b.name and b.name is null;

    总结规律

    从以上现象总结出左/右连接能够被CBO自动改写为内连接的条件为被驱动表(比如这里的b表)的过滤条件一定位于where后,并且条件不能为is null。

  • 相关阅读:
    iOS开发-类簇(Class Cluster)
    算法-有向图及可达性
    算法-无向图(连通分量,是否有环和二分图)
    算法-无向图(深度优先搜索和广度优先搜索)
    算法-无向图
    算法-散列表
    Red-Gate.NET.Reflector.v8.0.1.308(内含注册机Keygen与注册图解)
    [转]c#快捷键
    Windows常用性能计数器总结
    [转]C#程序性能优化
  • 原文地址:https://www.cnblogs.com/PiscesCanon/p/14233065.html
Copyright © 2011-2022 走看看