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。

原文地址:https://www.cnblogs.com/PiscesCanon/p/14233065.html