結合は実行時にwhere節に最適化されていますか?


14

このようなクエリを作成すると...

select *
from table1 t1
join table2 t2
on t1.id = t2.id

SQLオプティマイザーは、それが正しい用語であるかどうかはわかりませんが、それを...

select *
from table1 t1, table2 t2
where t1.id = t2.id

基本的に、SQL ServerのJoinステートメントはsqlを書くための簡単な方法ですか?それとも、実際に実行時に使用されますか?

編集:私はほとんど常に、そしてほとんど常にJoin構文を使用します。私は何が起こるのか興味があります。


1
「ほぼ」について詳しく説明していただけますか?古いスタイルの構文を使用するのはいつですか?
アーロンバートランド

2
あなたは(非推奨)追加した場合、それが違いを生むん一つのエッジケースがあるGROUP BY ALL
マーティン・スミス

@MartinSmith誰かが故意に使用GROUP BY ALLしていますか?:-)
アーロンバートランド

@AaronBertrand-私はそれを疑います!誰もがそれを使用するのを見たことがないと思います。
マーティンスミス

回答:


20

それらは内部的に同じものに崩壊します。前者は常に書くべきものです。さらに重要なのは、なぜ重要なのですか?実行計画とパフォーマンスの点では同じです(混乱しないと仮定すると、古いスタイルの怠zyな構文の方が簡単です)。

ここでは何があるというのAdventureWorksを使用していない証拠であるCROSS JOINfilter起こって。


明示的な結合:

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


暗黙的な結合:

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


ほら!同一の計画、同一の結果、クロスジョインまたはフィルターはどこにも見られません。

(明確にするためにSELECT、両方の場合の演算子の警告は、カーディナリティに影響する暗黙的な変換であり、どちらの場合も結合とは関係ありません。)


20

厳密に言えば、クエリオプティマイザーへの入力には2つの形式に違いがあります。

-- Input tree (ISO-89)
SELECT
    p.Name,
    Total = SUM(inv.Quantity)
FROM 
    Production.Product AS p,
    Production.ProductInventory AS inv
WHERE
    inv.ProductID = p.ProductID
GROUP BY
    p.Name
OPTION (RECOMPILE, QUERYTRACEON 8605, QUERYTRACEON 3604);

ISO-89入力ツリー

-- Input tree (ISO-92)
SELECT
    p.Name,
    Total = SUM(inv.Quantity)
FROM Production.Product AS p
JOIN Production.ProductInventory AS inv ON
    inv.ProductID = p.ProductID
GROUP BY
    p.Name
OPTION (RECOMPILE, QUERYTRACEON 8605, QUERYTRACEON 3604);

ISO-92入力ツリー

ご覧のとおり、ON句の述語は最新の構文を使用して結合に密接にバインドされています。古い構文では、論理的なクロス結合の後にリレーショナル選択(行フィルター)が続きます。

クエリオプティマイザーは、ほとんどの場合、最適化中にリレーショナル選択を結合に集約します。つまり、2つのフォームは同等のクエリプランを生成する可能性が非常に高くなりますが、実際の保証はありません。


4

内部結合の場合は交換可能ですが、外部結合の場合は意味が異なります-ONは一致し、WHEREは単純なフィルタリングです。そのため、ONでの正しいJOIN構文の一致に固執することをお勧めします。


4

OK、私は興味があったので、テストをしました。次の実行計画を実際に取得しました。

select * 
from sys.database_principals prin, sys.database_permissions perm
WHERE prin.principal_id = perm.grantee_principal_id

そして

select * 
from sys.database_principals prin
JOIN sys.database_permissions perm
    ON prin.principal_id = perm.grantee_principal_id

私はそれらをオブジェクトごとに比較しましたが、それらは同一でした。したがって、少なくとも非常に単純な例では、彼らは同じことを思いつきました。統計IOと時間もチェックしましたが、それらは同じものになるほど十分に近かったです。

そうは言っJOINても、特に複雑なクエリでは読みやすく、ミスをする可能性が低いため、構文を使用する必要があります。また、SQL Server 2005では、結合の*=/ =*構文OUTERは既に削除されています。

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