反连接比左外连接更有效吗?

时间:2017-09-23 18:33:10

标签: oracle

this answer的评论指出,反连接可能已经过优化,可以更有效地在Oracle中进行外连接。我有兴趣看看哪些解释/证据可能会支持或反驳这种说法。

2 个答案:

答案 0 :(得分:2)

在SQL查询中使用“not exists”或“not in”时,让Oracle选择合并反连接或散列反连接访问路径。

快速解释

例如,给定表A和B之间的连接(来自Ax = Bx上的A连接B),Oracle将从表A中获取所有相关数据,并尝试将它们与表B中的相应行匹配,因此它严格依赖于表A谓词的选择性。

使用反连接优化时,Oracle可以选择具有更高选择性的表并将其与另一个表匹配,这可能会导致更快的代码。

使用常规连接或子查询无法做到这一点,因为它不能假设表A和B之间的一个匹配足以返回该行。

相关提示: HASH_AJ,MERGE_AJ。

更多

This看起来像一篇关于这个主题的精彩而详细的文章。

Here是另一篇更重要的文章。

答案 1 :(得分:0)

如果Oracle可以将left join + where null变换为ANTI join,那么它就完全一样了。

create table ttt1 as select mod(rownum,10) id from dual connect by level <= 50000;
insert into ttt1 select 10 from dual;
create table ttt2 as select mod(rownum,10) id from dual connect by level <= 50000;

select ttt1.id
  from ttt1
  left join ttt2
    on ttt1.id = ttt2.id
 where ttt2.id is null;

select * from ttt1 where id not in (select id from ttt2);

如果你看一下

Final query after transformations:******* UNPARSED QUERY IS *******

在事件10053的跟踪中,您将找到两个完全相同的查询(您可以在跟踪文件的谓词中看到&#34; =&#34;因为ANTI连接没有特殊符号)< / p>

SELECT "TTT1"."ID" "ID" FROM "TTT2" "TTT2","TTT1" "TTT1" WHERE "TTT1"."ID"="TTT2"."ID"

他们有完全相同的计划

-----------------------------------
| Id  | Operation          | Name |
-----------------------------------
|   0 | SELECT STATEMENT   |      |
|   1 |  HASH JOIN ANTI    |      |
|   2 |   TABLE ACCESS FULL| TTT1 |
|   3 |   TABLE ACCESS FULL| TTT2 |
-----------------------------------

但是,如果你提示禁用转换,那么计划将是

select --+ no_query_transformation
       ttt1.id
  from ttt1, ttt2
 where ttt1.id = ttt2.id(+) and ttt2.id is null;

------------------------------------
| Id  | Operation           | Name |
------------------------------------
|   0 | SELECT STATEMENT    |      |
|   1 |  FILTER             |      |
|   2 |   HASH JOIN OUTER   |      |
|   3 |    TABLE ACCESS FULL| TTT1 |
|   4 |    TABLE ACCESS FULL| TTT2 |
------------------------------------

并且性能会显着下降。

如果你将ANSI连接语法与deisabled转换一起使用,那就更糟了。

select --+ no_query_transformation
       ttt1.id
  from ttt1
  left join ttt2
    on ttt1.id = ttt2.id
 where ttt2.id is null;
select * from table(dbms_xplan.display_cursor(format => 'BASIC'));

--------------------------------------------------
| Id  | Operation              | Name            |
--------------------------------------------------
|   0 | SELECT STATEMENT       |                 |
|   1 |  VIEW                  |                 |
|   2 |   FILTER               |                 |
|   3 |    MERGE JOIN OUTER    |                 |
|   4 |     TABLE ACCESS FULL  | TTT1            |
|   5 |     BUFFER SORT        |                 |
|   6 |      VIEW              | VW_LAT_2131DCCF |
|   7 |       TABLE ACCESS FULL| TTT2            |
--------------------------------------------------

因此,简而言之,如果Oracle可以将转换应用于ANTI连接,那么性能完全相同,否则可能会更糟。您还可以使用提示&#34; - + rule&#34;禁用CBO转换并查看发生的情况。

PS。另外,SEMI连接在某些情况下可能比内连接+更好,即使启用了CBO转换也是如此。