OUTER JOIN内にネストされたINNER JOINの構文とクエリ結果


10

TLDR; 2つの実行プランを見ると、どちらが良いのか簡単な答えはありますか?意図的にインデックスを作成しなかったので、何が起こっているのかを簡単に確認できます。

異なる結合スタイル(つまり、ネストされたものと従来のもの)の間のクエリパフォーマンスの違いを発見した私の以前の質問をフォローアップして、ネストされた構文もクエリの動作を変更することに気付きました。次の2つのクエリについて考えます。

SELECT  a.*, m.*, n.*
FROM    dbo.Autos a
LEFT JOIN dbo.Models m
  JOIN dbo.Manufacturers n  -- <-- Nested INNER JOIN
  ON n.ManufacturerID = m.ManufacturerID
ON m.ModelID = a.ModelID

ここに画像の説明を入力してください

これは、Modelsテーブルにない ModelIDを持つ自動行を含めるために、製造元を結合する必要はありません

ここに画像の説明を入力してください

従来の構文を使用して、結合をManufacturesから外部結合に変更する必要があります。ただし、これによりクエリプランが変更されます。

SELECT a.*, m.*, n.*
FROM dbo.Autos a
LEFT JOIN dbo.Models m
ON m.ModelID = a.ModelID
LEFT JOIN dbo.Manufacturers n -- <-- Now LEFT OUTER JOIN
ON n.ManufacturerID = m.ManufacturerID

ここに画像の説明を入力してください

回答:


12

2つの実行プランを見ると、どちらが良いのか簡単な答えはありますか?意図的にインデックスを作成しなかったので、何が起こっているのかを簡単に確認できます。

2番目の計画は推定コストが低いため、その限られた意味では「より良い」と言えます。

データセットが非常に小さいため、オプティマイザは代替手段を探すのにあまり時間をかけませんでした。クエリの最初の形式は、ハッシュ結合とテーブルスプールを使用して早い段階でプランを見つけることです。その計画の推定コストは非常に低いので、オプティマイザはより良いものを探す気になりません。

クエリの2番目の形式は、検索プロセスの早い段階でネストされたループの外部結合のみを使用してプランを見つけることがあり、再びオプティマイザがプランが十分であると判断します。たまたまこの計画の方が安いと推定されている。

とはいえ(質問のコメントで述べたように)、2つのクエリは意味的に同一ではありません。データベースの将来のすべての状態で結果が常に同じであることを保証できる場合、これは重要ではありませんが、オプティマイザはその仮定を行うことができません。すべての状況において、SQLによって指定された同じ結果を生成することが保証されている計画のみを生成します。

ネストされた構文はクエリの動作も変更することに気づきました。

「ネストされた構文」は、ANSI結合構文仕様全体の1つの側面にすぎません。より複雑な結合パターンの完全な論理仕様を有効にするために、仕様では(オプションの)括弧とFROM節のサブクエリを許可しています。

クエリは括弧を使用した同じANSI構文使用して記述できます。

SELECT
    A.*,
    M.*,
    N.* 
FROM dbo.Autos AS A
LEFT JOIN
(
    dbo.Manufacturers AS N
    JOIN dbo.Models AS M
        ON M.ManufacturerID = N.ManufacturerID
) ON M.ModelID = A.ModelID;

このフォーム論理要件は左から参加することを明らかに示しているAutos結果、内側接合ManufacturersしますModels。オプションの括弧を省略すると、「ネストされた」という形式になります。

SELECT
    A.*,
    M.*,
    N.* 
FROM dbo.Autos AS A
LEFT JOIN dbo.Manufacturers AS N
JOIN dbo.Models AS M
    ON M.ManufacturerID = N.ManufacturerID
    ON M.ModelID = A.ModelID;

これは別の構文ではありません-オプションの括弧を省略し、少し再フォーマットするだけです。

マーティンが述べたように、この場合、内部結合とそれに続く右外部結合を使用して論理要件を表現することもできます。

SELECT
    A.*,
    M.*,
    N.* 
FROM dbo.Manufacturers AS N
JOIN dbo.Models AS M
    ON M.ManufacturerID = N.ManufacturerID
RIGHT JOIN dbo.Autos AS A
    ON A.ModelID = M.ModelID;

上記の3つのクエリ形式はすべて、同じANSI結合構文を使用します。3つとも、提供されたデータセットを使用して同じ物理実行プランを生成することもあります。

共通実行計画

前の質問への回答で述べたように、まったく同じ論理要件を表すクエリが常に同じ実行プランを生成するとは限りません。どの論理クエリフォームを使用するかは、主にスタイルの問題です。一般的に、特定のスタイルと「より良い」クエリプランの間には相関関係はありません。新しいクエリが元のクエリと完全に論理的に同一でない場合は、通常、クエリを書き直して特定のプランを取得しないことをお勧めします。

SQL標準ではFROM句のサブクエリも許可されているため、同じクエリ仕様を記述する別の方法は次のとおりです。

SELECT * 
FROM dbo.Autos AS A
LEFT JOIN
(
    SELECT
        N.ManufacturerID,
        ManufacturerName = N.Name,
        M.ModelID,
        ModelName = M.Name
    FROM dbo.Manufacturers AS N
    JOIN dbo.Models AS M
        ON M.ManufacturerID = N.ManufacturerID
) AS R1
    ON R1.ModelID = A.ModelID;

従来の構文を使用して、結合を「製造元から外部結合へ」というように変更する必要がありますが、これによりクエリプランが変更されます。

これはおそらくクエリの意味を変更します。その場合、それは技術的に有効な代替手段ではありません(ただし、質問に対するypercubeコメントを参照してください)。

ANSI結合構文の(オプションの)括弧は、このようなより複雑な結合要件のために正確に存在するので、必要な場所でそれらを使用することをためらわないでください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.