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。

  • 相关阅读:
    RESTful 、RESTful API 、REST 介绍
    微服务 第三章:SpringBoot 创建web项目(调用jsp)
    微服务 第二章:SpringBoot 创建web项目(用Thymeleaf模板引擎)
    SpringBoot学习之 Thymeleaf
    Junit测试
    ---run-pat 测试 crontab 命令
    ---iproute2 策略路由
    ---曾经整混的两个词
    ---Under Ubuntu 14.04
    ---Ubuntu 14.04 虚拟机器和主机时间同步
  • 原文地址:https://www.cnblogs.com/PiscesCanon/p/14233065.html
Copyright © 2011-2022 走看看