JOINまたはWHERE内の条件


192

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'

あなたはどちらを好みますか(そしておそらくなぜですか)?


4
2つのクエリを実行しましたか?2つのクエリによって生成された実行プランを確認しましたか?何を観察しましたか?
S.Lott、2009年

21
@ S.Lott、このクエリは例示のみを目的としています。私は、「もしあれば」というのが望ましい方法である「一般的に」疑問に思っています。
スティーブDignan

1
@Steve Dignan:これをサンプルデータでベンチマークし、クエリプランを確認する必要があります。答えは非常にはっきりしています。そして-おまけ-より複雑な状況が発生したときに再利用できるコードの断片があります。
S.Lott、2009年

1
条件が関係を記述している場合は、個人的にJOIN句に条件を入れます。結果セットをフィルターするだけの一般的な条件は、WHERE部分に移動します。例FROM Orders JOIN OrderParties ON Orders.Id = OrderParties.Order AND OrderParties.Type = 'Recipient' WHERE Orders.Status = 'Canceled'
Glutexo、2016年

回答:


153

リレーショナル代数を使用すると、WHERE句との述語を交換できますINNER JOIN。そのため、句を含むINNER JOINクエリでもWHERE、オプティマイザによって述語を並べ替えることができるため、処理中に述語を除外でき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

しかし、それはもちろん異なります。


7
きれいなクエリや読みやすさだけでなく、パフォーマンスも重要です。結合に条件を設定すると、適切にインデックスが作成されたテーブルで大量のデータのパフォーマンスが向上します。
Shahdat

1
数百万のレコードで5〜6のテーブルを結合する月次売上レポートを実行するだけです。
パフォーマンスが

2
@Shahdatを使用すると、where句から内部結合にフィルター条件を移動してパフォーマンスに大きな違いが生じた場合、それらの実行プランをポストする必要があります。
Cade Roux

4
@Cade実行計画を調査しました-どちらのシナリオも同じコストを示しています。クエリを複数回実行すると、どちらもほぼ同じ時間がかかるようです。以前は、本番環境でクエリを実行しており、データベースがライブユーザーによって使用されていたため、パフォーマンスに大きな違いがありました。その混乱でごめんなさい。
Shahdat 2016年

4
この回答はINNER JOINには適切ですが、左/右結合には適していません。
2017年

121

内部結合の場合、私は実際には違いに気づきませんでした(ただし、すべてのパフォーマンスチューニングと同様に、自分の条件下でデータベースと照合する必要があります)。

ただし、条件をどこに置くかは、左結合または右結合を使用している場合に大きく異なります。たとえば、次の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'

最初のものは、2009年5月15日より後に日付が付けられたレコードのみを提供するため、左結合が内部結合に変換されます。2番目は、これらのレコードと、注文のない顧客を示します。結果セットは、条件をどこに置くかによって大きく異なります。(例としてのみ使用する場合は、*を選択してください。もちろん、実稼働コードでは使用しないでください。)これの例外は、1つのテーブルのレコードのみを表示し、他のテーブルのレコードは表示しない場合です。次に、結合ではなく条件にwhere句を使用します。

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderID is null

例を使って説明していただきありがとうございます
Rennish Joseph

1
「したがって、左結合を内部結合に変換する」。どうやって?もう少し詳しく説明してもらえますか?
user1451111 2018

@ user1451111 LEFT / RIGHT JOINが返すものについて学習します。INNERJOIN行と、NULLによって拡張された一致しない左/右テーブル行。FULL JOINは、NULLによって拡張された、一致しない左右のテーブル行であるUNION ALLのINNER JOIN行を返します。OUTER JOINの一部としてどのINNER JOINが必要かを常に把握してください。OUTER JOIN ONがNULLによって拡張された行を削除した後、つまりNULLで拡張された可能性のある列がNULLでないことを必要とするWHEREまたはONは、INNER JOIN行のみを残します。
philipxy

1
@ user1451111または、より簡単に言うとA left join B、Aのすべての行がBの一致するすべての行に結合されます。Bに一致する行がない場合、A列には値がありますが、その行のBのすべての列はNULL値として表示されます。書き込んwhere B.somecolumn = ‘somevalue’だ場合、NULL(B.somecolumn)が 'somevalue'と比較されます。NULLと比較したものはすべてfalseであるため、A行に対応するB行がないすべての行が削除され、得られる結果はINNER JOINと同じになるため、外部結合は内部結合になります
Caius Jard 2018

はい私は結果が同じであることを確認しました:SELECT fans.id、prospects.id FROM funds内部結合プロスペクト(prospects.id = Funds.lead_idおよびProspects.is_manual = 'no')およびSELECT Funds.ID、Prospects.id FROM funds左(prospects.id = Funds.lead_id)で見込客を結合します。ここで、prospects.is_manual = 'no'
Rohit Dhiman

25

ほとんどのRDBMS製品は、両方のクエリを同じように最適化します。Peter GulutzanとTrudy Pelzerによる「SQLパフォーマンスチューニング」では、RDBMSの複数のブランドをテストしましたが、パフォーマンスに違いはありませんでした。

結合条件をクエリ制限条件とは別にしたい。

使用しているOUTER JOIN場合は、結合句に条件を設定する必要があります。


1
構文的にはクリーンであり、その本の知識と非常に高い評判に任せなければならないことに同意しますが、先週の4つのクエリは、実行プラン、CPU時間、論理読み取りが非常に異なる場合に考えられます。述部が結合に移動しました。
marr75

2
あなたはベストプラクティスについて尋ねていました。特定のRDBMS実装がどのように機能するかをテストするようになるとすぐに、他の人々がベンチマークという正しいアドバイスをしました。
ビルカーウィン、

12

JOINが発生した後、WHEREはフィルタリングします。

JOINでフィルタリングして、JOINプロセス中に行が追加されないようにします。


10
意味的には、これらはINNER JOINプロセスの間は回避されますが、オプティマイザはINNER JOINとWHERE述語を自由に再配置できるため、オプティマイザは必要に応じて後で自由に除外できます。
Cade Roux、

1
Cade Roux:そうです。多くの場合、SQLで記述したものは、すべてが言われて完了したときにオプティマイザが提供するものではありません。これはすべての理論の世界で正しいと思いますが、自動クエリオプティマイザの世界では、あなたの答えはもちろんより正確です:)
TheTXI

私はこの状態の説明が好きですON
ロバート・ロチャ

3

完全なテーブル/ビューを結合してから、結果セットの述語を導入するためにWHEREを使用するように結合することを好みます。

構文的にすっきりした感じです。


2

通常、結合でフィルタリングするとパフォーマンスが向上します。特に、両方のテーブルのインデックス付き列で結合できる場合。ほとんどのクエリでもこれを行うことで、論理読み取りを削減できるはずです。つまり、大容量環境では、実行時間よりもはるかに優れたパフォーマンスインジケータです。

誰かがSQLベンチマークを示し、開発サーバーで真夜中にsprocの両方のバージョンを50,000回実行し、平均時間を比較したとき、私は常に穏やかに面白がっています。


0

JOINが「対象」ではないため、条件を結合に入れることは「意味的に間違っている」ように見えます。しかし、それは非常に定性的です。

追加の問題:内部結合から正しい結合に切り替える場合、条件がJOIN内にあると、予期しない結果が生じる可能性があります。


3
これらの結果は、「期待」されたり、「意図的」になったりすることがあります(たとえば、WHERE条件がJOIN条件とは異なるセマンティクスを持つ外部結合など)。
Marcel Toth、2012年

0

テーブルが大きいほど、結合は速いと私は考えています。それは実際にはそれほど大きな違いではありませんが、特に小さいテーブルを扱っている場合はそうです。結合について初めて知ったとき、結合の条件はwhere句の条件と同じであり、条件を実行するテーブルについてwhere句が特定されていれば、条件を交換して使用できると言われました。


-4

結合に条件を追加することをお勧めします。読みやすさよりもパフォーマンスの方が重要です。大規模なデータセットの場合は重要です。


1
何らかの証拠があります。前述の述語の配置がパフォーマンスにどのように影響するかを調査しますか?
Zso
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.