44

次の T-SQL コードがあるとします。

SELECT * FROM Foo f
INNER JOIN Bar b ON b.BarId = f.BarId;
WHERE b.IsApproved = 1;

次の例も同じ行セットを返します。

SELECT * FROM Foo f
INNER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId);

これはここでの最良のケースのサンプルではないかもしれませんが、これら 2 つの間にパフォーマンスの違いはありますか?

4

5 に答える 5

46

外部結合との違いに注意してください。の条件にb.IsApproved(右の表のバー)のフィルターが追加されたクエリ:ONJOIN

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId); 

句にフィルターを配置することと同じではありません。WHERE

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved = 1); 

「失敗した」外部結合(つまり、 aBarがない場所) の場合、これはそのような失敗したすべての結合行として残され、これらの行はフィルターで除外されます。b.BarIdf.BarIdb.IsApprovedNULL

別の見方をすると、結合が失敗した場合でも LEFT テーブルの行が返されることが保証されているため、最初のクエリでLEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId)は常にLEFT テーブルの行が返されるということです。LEFT OUTER JOINただし、 on 条件に追加(b.IsApproved = 1)すると、が false のLEFT OUTER JOIN場合に右のテーブル列が NULL になります。つまり、条件 on に(b.IsApproved = 1)通常適用されるのと同じ規則に従います。LEFT JOIN(b.BarId = f.BarId)

更新: コンラッドが尋ねた質問を完了するには、OPTIONAL フィルターの同等の LOJ は次のようになります。

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved IS NULL OR b.IsApproved = 1);

つまり、このWHERE句では、結合が失敗(NULL)してフィルターが無視されるかどうかと、結合が成功してフィルターを適用する必要がある場合の両方の条件を考慮する必要があります。(b.IsApprovedまたはb.BarIdテスト可能NULL)

ここにSqlFiddle をまとめました。これはb.IsApprovedJOIN.

于 2012-04-24T11:53:59.760 に答える
32

いいえ、クエリ オプティマイザーは、両方の例で同じ実行プランを選択できるほどスマートです。

SHOWPLAN実行計画を確認するために使用できます。


ただし、すべての結合接続をON句に配置し、すべての制限を句に配置する必要がありますWHERE

于 2012-04-24T11:50:54.910 に答える
6
SELECT * FROM Foo f
INNER JOIN Bar b ON b.BarId = f.BarId
WHERE b.IsApproved = 1;

これがより良い形です。読みやすく、変更も簡単です。ビジネスの世界では、これはあなたが行きたいと思うものです。ただし、パフォーマンスに関しては同じです。

于 2012-04-24T11:51:45.890 に答える
0

最近のバージョンの MSSQL でもオプティマイザが十分に賢くなく、パフォーマンスの差が非常に大きかった場合がいくつかあるようです。

ただし、これは例外です。ほとんどの場合、SQL Server オプティマイザーが問題を解決し、適切な計画を立てます。

そのため、WHERE 句でフィルターを使用するポリシーを維持し、必要に応じて最適化してください。

于 2012-04-24T19:45:02.207 に答える