web-dev-qa-db-ja.com

複数の結合があるSQLクエリの実行プランの論理的な順序

私はSQLクエリの実行の論理的な順序を知っています:

FROM
ON
JOIN
WHERE
GROUP BY
WITH CUBE or WITH ROLLUP
HAVING
SELECT
DISTINCT
ORDER BY
TOP

たとえば、次のようなクエリがある場合、クエリに複数の結合があるとどうなりますか。

SELECT *
FROM user_branch T1
INNER JOIN dimcustomer2 T2
   ON T1.BRANCH_CODE = T2.BRANCH_CODE
INNER JOIN customer_guarantee T3
   ON T3.CUSTOMER_NUM = T2.CUSTOMER_NUM

データの例:

customer_guarantee:    CUSTOMER_NUM      BRANCH_CODE
                      -------------------------------
                           A                X
                           B                X
                           C                Y
                           D                Z



 user_branch:           USER_ID          BRANCH_CODE    
                      --------------------------------
                           U1               Y



 dimcustomer2:         CUSTOMER_NUM      BRANCH_CODE      
                      --------------------------------
                           A                Y
                           B                Y
                           C                Y
                           D                Z

これはどのように実行されますか?どの結合が最初に実行されますか?そして、クエリに異なる種類の結合がある場合はどうなりますか?その場合、結合を実行する順序はどうなりますか?前もって感謝します。

4
Pantea Tourang

結合の論理的な順序を決定する1つの方法は、例の最初の内部結合を左外部結合に置き換えることです。

SELECT *
FROM user_branch T1
LEFT  JOIN dimcustomer2 T2
   ON T1.BRANCH_CODE = T2.BRANCH_CODE
INNER JOIN customer_guarantee T3
   ON T3.CUSTOMER_NUM = T2.CUSTOMER_NUM

T1の一部の行がT2に一致しないと仮定します。より具体的には、これらが3つのテーブルであると仮定します。

    T1                         T2                           T3

BRANCH_CODE          BRANCH_CODE  CUSTOMER_NUM          CUSTOMER_NUM
-----------          -----------  ------------          ------------
11                   11           230                   120
12                   12           235                   170
13                   15           260                   230
14                                                      235
15                                                      245
                                                        250
                                                        260
                                                        270

ここには2つの結合があり、それらが実行される順序には2つの可能性があります。

1. LEFT JOIN、次にINNER JOIN

左結合が最初に評価される場合、その結果はT2行が一致しなかったT1列にnullが含まれます。

 T1.BRANCH_CODE T2.BARNCH_CODE T2.CUSTOMER_NUM 
 -------------- -------------- --- ------------ 
 11 11 230 
 12 12 235 
 13 (ヌル)(ヌル)
 14 (ヌル)(ヌル)
 15 15 260 

T3列を使用する条件で内部結合を使用して、T2でその結果をさらに結合すると、一致しない、つまり対応するT1行が削除されます。これは、nullが結合の等号条件を満たすことができないためです。

 T1.BRANCH_CODE T2.BARNCH_CODE T2.CUSTOMER_NUM T3.CUSTOMER_NUM 
 -------------- -------------- --------------- --------------- 
 11 11 230 230 
 12 12 235 235 
 15 15 260 260 

このようにして、T1行の一部が最終的な結果セットから除外されます。

2. INNER JOIN、次にLEFT JOIN

内部結合が最初に実行されると、内部結合の条件に一致するT2およびT3の行を含む結果セットが生成されます。

 T2.BARNCH_CODE T2.CUSTOMER_NUM T3.CUSTOMER_NUM 
 -------------- ---------------- ------------- 
 11 230 230 
 12 235 235 
 15 260 260 

この結果セットがT1に外部結合され、T1が外部にある場合、T1からのすべての行と、外部結合条件に一致するT2-T3内部結合からの行を含む最終結果が得られます。

 T1.BRANCH_CODE T2.BARNCH_CODE T2.CUSTOMER_NUM T3.CUSTOMER_NUM 
 -------------- -------------- --------------- --------------- 
 11 11 230 230 
 12 12 235 235 
 13 (ヌル)(ヌル)(ヌル)
 14 (ヌル)(ヌル)(ヌル)
 15 15 260 260 

したがって、この2番目の解釈は、すべてのT1行が結果に存在する必要があることを意味します。


これらの2つの解釈はそのような異なる結果を与えるので、1つだけが真であることは明らかです。クエリを実行すると、実際には最初のクエリであることがわかります。つまり、論理的には、結合はFROMで指定された順序で実行されます。

構文のバリエーション

上記の結論は、最も一般的な結合構文、つまりこれに適用されることに注意してください。

FROM
  T1
  ... JOIN T2 ON ...
  ... JOIN T3 ON ...
  ...

あなたの例はそのパターンに一致するので、結論もそれに当てはまります。しかし、私たちの結論が当てはまらない、または少なくともそれほど単純ではない場合に言及する価値のあるバリエーションがあります。

1.ネストされたJOIN構文

構文的には、次のように、結合を別の結合内に指定できます。

FROM
  T1
  JOIN
    T2
    JOIN T3 ON ..
  ON ...

上記の場合、JOIN T2の前にJOIN T3が出現します。ただし、前の結合の宣言はその時点では完了していません。そのON副次句は最後のものであり、JOIN T3 ON ...部分の後でのみ論理的に評価されます。したがって、この場合、T2は最初にT3に結合され、次に結合の結果がT1に結合されます。

あなたは、私たちの結論がここにあると主張しますが、この状況ではそれほど明確ではありません。結合は、FROM句でspecifiedの順序で評価されると結論付けました。この例では、FROM句を解析するときに最初に遭遇する結合は、2番目の結合の時点ではまだ完全に指定されていません。

2.コンマ結合と従来の結合の混合

明示的なJOIN構文が導入される前は、結合は次のように指定されていました。

FROM
  T1,
  T2,
  T3
WHERE
  <joining conditions, filter conditions>

このタイプの結合は、コンマ結合と呼ばれることもありますが、SQL Serverを含む、すべてではないにしても、ほとんどのプラットフォームでサポートされています。

結合条件がない場合、コンマ結合は基本的にクロス結合です。結合条件は、それを内部結合にします。ただし、この場合の結合条件は、まったく別の句、WHERE句に入っていることがわかります。

SQL Serverでは、同じFROM句にコンマ結合と従来の結合を混在させることができます。次のような結合が混在している場合:

FROM
  T1,
  T2
  JOIN T3 ON ... ,
  T4 ...

SQL Serverは、コンマで区切られた個々の項目を互いに独立して評価してから、それらをすべて結合します。したがって、上記の場合、T2 JOIN T3 ON ...結合は、その結果がT1にクロス結合される前に評価されます(WHERE句で検出される可能性のある結合条件によってさらにフィルタリングされます)。ここでの結論はまったく当てはまりません。ただし、この場合、非常に異なる構文が使用されていることがわかります。

スタックオーバーフローに関する私の回答で混合構文について少し詳しく説明します: マルチパート識別子をバインドできませんでした

11
Andriy M

「論理的実行」というフレーズはあまり意味がありません。クエリ実行は、定義により、結果セットの物理的な具体化です。 「論理的実行」とは、クエリのコンパイル、つまりクエリ構文と意味の意味が分析され、クエリの計画がその意味の意味を実装するために準備されるフェーズであると私は思います。

結合されたテーブル1 クエリでは常に左から右(または上から下)に評価されます。

select ... from t_a                   -- evaluated first
           join t_b                   -- evaluated second
             on t_a.c1 = t_b.c3
           join t_x                   -- evaluated third
             on t_b.c4 = t_x.c5
           ...

評価シーケンスの後半に含まれるテーブルに属する列をON句で参照しようとすると、これを自分で確認できます。これはコンパイルに失敗します:

select ... from t_a
           join t_b
             on t_a.c1 = t_c.c8       -- t_c is not known yet
           join t_c                   
           ...

クエリが解析された後、実行プランは、クエリのセマンティクスを維持するanyの順序で結合を実行できます。 マニュアルによると

FROMキーワードの後のテーブルソースの順序は、返される結果セットには影響しません。

このQ&A はある程度関連しています。


1-joined_table句は、2つのtable_sourcesとそれに対応するON句で構成されます。

9
mustaccio

すべてのJOINは実際にはFROM句に属しています。意味的には、ON句を維持し、LEFT/RIGHT OUTER JOIN句を使用しない限り、JOINが書き込まれる順序に違いはありません。言い換えると、FROM句とJOIN句の出力は単一の大きなリレーションであり、列がどの順序であるかは実際には問題ではありません。これはデータベースオプティマイザーにとって重要な最適化の機会であるため、これは非常に重要です。WHERE条件によってプルーニングされる可能性がある場合は、最初に小さいリレーション間でJOINを実行するのが理にかなっています。この方法では、結果セットの残りの部分を処理するときに、データベースがこれらの列をキャッシュする方が現実的です。

2
MauganRa