2012-03-15 6 views
7

Oracle 11のFULL OUTER JOINの奇妙な動作に気付きました。私はHRスキーマ、特にEMPLOYEESとDEPARTMENTSからテーブルを結合していました。 - 私はselect句で特定の列のセットを入れたときに、クエリが122行(Aを返しますOracleの完全外部結合の異常な動作 - どのように説明できますか?

SELECT * FROM employees e 
    FULL JOIN departments d ON e.department_id = d.department_id 

しかし、理解するのが難しいものです。たとえば、次のクエリは、123行を返す

行が欠落すると、割り当てられた部門を持たない従業員のためである - さらに左に返される1は内部結合と比較して参加):私は、行を数える場合でも

SELECT first_name, last_name, department_name FROM employees e 
    FULL JOIN departments d on e.department_id = d.department_id 

それは122(COUNT(*))を返します!!!何が起こっている? SELECT *SELECT COUNT(*)の違いは何ですか?

SELECT * ...のための計画を説明します。

SELECT STATEMENT          122 
    VIEW     VW_FOJ_0      122 
    HASH JOIN       FULL OUTER  122 
     Access Predicates 
     E.DEPARTMENT_ID = D.DEPARTMENT_ID 
     TABLE ACCESS  DEPARTMENTS  FULL   27 
     TABLE ACCESS  EMPLOYEES  FULL   107 

SELECT COUNT(*) ...用:

SELECT STATEMENT            1 
    SORT          AGGREGATE   1 
    VIEW    VW_FOJ_0       122 
     HASH JOIN       FULL OUTER  122 
     Access Predicates 
      E.DEPARTMENT_ID = D.DEPARTMENT_ID 
     INDEX   DEPT_ID_PK   FAST FULL SCAN 27 
     INDEX   EMP_DEPARTMENT_IX FAST FULL SCAN 107 
+2

あなたは、これらの列のための 'union'を使用している場合はどうなりますか:これらの例はかなりの数では、この問題を回避するには、「ネイティブ」完全外部この文を使用して、現在のセッションのために行うことができ、参加し無効にすることです? 'union all'を使うときに何か違うものを得ますか?あなたが 'group by first_name、last_name、department_name'と数えれば何が得られますか? –

+0

'SELECT * FROM従業員e FULL JOIN部署d on e.department_id = d.department_id'は123行を返し、従業員からのSELECT件数(*)はe部署の全部署dはe.department_id = d.department_id'で122行を返しますか? –

+0

はい、まさにこの質問を投稿した理由です。 –

答えて

5

にオプティマイザがに選ぶべきでない理由をただし、説明すべきです2番目のクエリでEMP.DEPT_IDのインデックスを使用します。これはNULL値を持つことができるためです。これは結果から1行を除外する原因となります。

現時点で私が考えることができる唯一のバグのない説明は、DISABLE RELYモードで制約を何らかの形で作成したため、フィールドにNULLを含めることができないとオプティマイザが考えるようになっていることです。この場合、制約内の誤った情報を指定してインデックスを使用するのは正しいでしょう。しかし、RELYオプションはNOT NULL制約では使用できないようですので、どのように問題になるかはわかりません。それにもかかわらず、テーブルのすべての制約を注意深く見てください。

それ以外に、Oracleのサイトには完全な外部結合の間違った結果に関する驚くほど多くのバグがあります。あなたはそれらの1つを押すかもしれません。

alter session set "_optimizer_native_full_outer_join"=off; 
+0

+1:もっともらしい説明のようです。 DBのバージョンを知ることは面白いだろう。 –

1

(コメントでこれを書くことができません)

結果は実行計画に適合しています。

count(*)実行計画は、employess表のすべてのdept_idsを含む索引EMP_DEPARTMENT_IXを使用します。しかし、索引にはNULLは含まれません。したがって、この実行計画では、department_idがNULLのempsを "失う"でしょう。

Oracleは反対で

select first_name, last_name, department_name 

select count(*) 

の場合には、この実行計画を選択

select * 
+1

はい、同意します。しかし、これは私の意見では一種の矛盾です。 *を選択する場合を除いて、完全な外部結合は機能しません。 –

+0

@luckyjaca 'select emp_id'、' select first_name'、 'select e.department_id'、' select d.department_id'、 'select d.department_name'などでもっとテストできますか? –

+0

heh ...私はあなたが示唆したようにテストを行った。それにもかかわらず、すべてが122行を返しました.123行を取得する唯一の方法は、アスタリスクですべての列を選択することです。しかし、最後に私はヒントを使用して123行を返すことができました: '/ * + no_index(e)* /'。 'COUNT(*)'または 'first_name、last_name、department_name'のように、すべてのクエリを動作させるだけで十分です。 –

関連する問題