JOIN句とWHERE句に条件を置くことの間に違い(パフォーマンス、ベストプラクティスなど)はありますか?
例えば...
-- Condition in JOIN
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD
ON CUS.CustomerID = ORD.CustomerID
AND CUS.FirstName = 'John'
-- Condition in WHERE
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD
ON CUS.CustomerID = ORD.CustomerID
WHERE CUS.FirstName = 'John'
どちらが好きですか(そしておそらくその理由は?)
関係代数により、WHERE
句とINNER JOIN
の述語の互換性が可能になるため、WHERE
句を含むINNER JOIN
クエリでも、オプティマイザによって再配置された述語を持つことができるため、は既に除外JOIN
プロセス。
クエリを可能な限り読みやすい方法で記述することをお勧めします。
これには、INNER JOIN
を比較的「不完全」にして、フィルタリング基準のリストをより保守しやすくするためにWHERE
にいくつかの基準を入れることが含まれる場合があります。
たとえば、次の代わりに:
SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
ON ca.CustomerID = c.CustomerID
AND c.State = 'NY'
INNER JOIN Accounts a
ON ca.AccountID = a.AccountID
AND a.Status = 1
書きます:
SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
AND a.Status = 1
しかし、それはもちろん異なります。
内部結合の場合、実際には違いに気付きませんでした(ただし、すべてのパフォーマンスチューニングと同様に、条件に応じてデータベースをチェックする必要があります)。
ただし、左結合または右結合を使用している場合、条件をどこに置くかによって大きな違いが生じます。たとえば、次の2つのクエリを検討してください。
SELECT *
FROM dbo.Customers AS CUS
LEFT JOIN dbo.Orders AS ORD
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderDate >'20090515'
SELECT *
FROM dbo.Customers AS CUS
LEFT JOIN dbo.Orders AS ORD
ON CUS.CustomerID = ORD.CustomerID
AND ORD.OrderDate >'20090515'
1つ目は、日付が2009年5月15日以降のレコードのみを提供するため、左結合を内部結合に変換します。 2番目は、これらのレコードと、注文のない顧客を提供します。結果セットは、条件をどこに置くかによって大きく異なります。 (例の目的のみで、もちろん運用コードで使用しない場合は*を選択します。)これの例外は、一方のテーブルのレコードのみを表示し、他方のテーブルは表示しない場合です。次に、結合ではなく条件にwhere句を使用します。
SELECT *
FROM dbo.Customers AS CUS
LEFT JOIN dbo.Orders AS ORD
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderID is null
ほとんどのRDBMS製品は、両方のクエリを同様に最適化します。 Peter GulutzanとTrudy Pelzerによる「SQL Performance Tuning」では、複数のブランドのRDBMSをテストしましたが、パフォーマンスの違いは見つかりませんでした。
結合条件をクエリ制限条件から分離することを好みます。
OUTER JOIN
を使用している場合、join句に条件を指定する必要がある場合があります。
WHEREは、JOINが発生した後にフィルタリングされます。
JOINでフィルタリングして、JOINプロセス中に行が追加されないようにします。
JOINを使用して完全なテーブル/ビューを結合し、WHEREを使用して結果セットの述語を導入することを好みます。
構文的にすっきりしています。
通常、結合でフィルタリングするとパフォーマンスが向上します。特に、両方のテーブルのインデックス列で結合できる場合。ほとんどのクエリでもこれを行うことで論理読み取りを削減できるはずです。これは、大容量環境では、実行時間よりもはるかに優れたパフォーマンスインジケータです。
誰かが自分のSQLベンチマークを表示し、開発サーバーで深夜にsprocの両方のバージョンを50,000回実行し、平均時間を比較したとき、私はいつも穏やかに面白がっています。
JOINが「目的」ではないため、条件を結合に入れることは「意味的に間違っている」ように思えます。しかし、それは非常に定性的です。
追加の問題:内部結合から、たとえば正しい結合に切り替える場合、JOIN内に条件があると、予期しない結果が生じる可能性があります。
結合に条件を追加することをお勧めします。パフォーマンスは読みやすさよりも重要です。大規模なデータセットの場合、重要です。
私の意見では、テーブルが大きいほど結合は速くなります。特に小さなテーブルを扱っている場合は特に違いはありません。結合について最初に学んだとき、結合の条件はwhere句の条件と同じであり、where句が条件を実行するテーブルについて特定である場合、それらを交換可能に使用できると言われました。