2017-09-23 12 views
3

this answerへのコメントは、アンチ・ジョインがOracleの外部ジョインより効率的に最適化されている可能性があることに注意してください。私は、どのような説明/証拠がこの主張を裏付けるか、あるいは否定するかを見ることに興味があります。anti-joinは、左外部結合より効率的ですか?

+0

実行計画と効率性については、ジョナサン・ルイスの記事は常に読める価値があることがわかります。 (JonathanはOTNに定期的に参加しています - OracleとSQL/PL/SQLのディスカッション・フォーラム、そしてOracle最適化に関する知識の豊かな人々の1人です)ここでは例題があります。フィルタとの定期的な結合に参加してください "と述べていますが、私の意見では、それぞれの場合に何が起こるかを知るために十分な議論があります。 https://jonathanlewis.wordpress.com/2015/04/13/not-exists/ – mathguy

+0

Jonathan Lewisの参考に感謝します。彼のものはいつもうまくいっている。 –

答えて

1

SQL問合せに「not exists」または「not in」を使用すると、Oracleにマージ・アンチ・ジョインまたはハッシュ・アンチ・ジョイン・アクセス・パスを選択させることができます。 Oracleは、テーブルAからのすべての関連データを取得し、対応する行でそれらを一致しようとする(Aからアックス= Bxの上にBを結合する)表AおよびB betwen参加所与例えば

クイック説明

、表Bでは、表Aの述部の選択性に厳密に依存しています。

アンチ・ジョイン最適化を使用すると、Oracleは選択性の高い表を選択し、他の表と一致させることができます。

通常の結合またはサブクエリでは、テーブルAとテーブルBの一致が1つあると仮定することはできません。

関連ヒント: HASH_AJ、MERGE_AJ。

より:

Thisは、件名に素晴らしく、詳細な記事のように見えます。

Hereは、他のデンケート記事です。

0

Oracleが左結合+nがANTI結合に変換できる場合は、まったく同じです。

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); 

あなたがイベント10053のトレースで

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

を見ている場合、あなたは2まったく同じクエリを見つけることができます(あなたがトレースファイルに述語に「=」を参照してくださいすることができますので、そこにANTIのための特別な記号)

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 | 
----------------------------------- 
01あなたは、しかし、変換を無効にするヒントを置く場合

その後、計画は

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結合構文を使用すると、さらに悪化します。

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結合に変換を適用できる場合は、パフォーマンスはまったく同じです。それ以外の場合は悪化する可能性があります。ヒント「+ルール」を使用してCBO変換を無効にし、何が起こっているかを見ることもできます。

PS。別の注記では、有効なCBO変換を使用しても、SEMI結合が内部結合+別名よりも優れている場合があります。

関連する問題