ONとWHEREのインデックスパフォーマンス


26

私は2つのテーブルを持っています

@T1 TABLE
(
    Id INT,
    Date DATETIME
)

@T2 TABLE
(
    Id INT,
    Date DATETIME
)

これらのテーブルには、(Id、Date)に非クラスター化インデックスがあります

そして、私はこれらのテーブルに参加します

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
WHERE 
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

これは次のように書くこともできます

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
    AND
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

私の質問は、これら2つのクエリのどちらがより良いパフォーマンスを提供するか、そしてその理由は何ですか?またはそれらは等しいですか?


1
すべてのフィールドをカバーする非クラスター化インデックスがあり、クラスター化インデックスがない @table変数が本当にありますか?または単純化ですか?
レムスルサヌ

1
それは極端な単純化です
エリックBergstedt

回答:


32

パフォーマンスは同じになります。オプティマイザーはこれを認識し、同じプランを作成します。

一方、彼らが等しいとは言いません。質問の最初の形式ははるかに読みやすく、一般的に期待されています。

手元にあるいくつかのテーブルを使用した例では、クエリをどのように記述しても、実行プランはまったく同じであることがわかります。

独自のテーブルとデータセットのクエリプランを決定して、状況で何が起こるかを確認できる必要があります。

SELECT * FROM salestable , custtable 
WHERE salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable 
JOIN  custtable 
ON salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable JOIN custtable 
ON salestable.custaccount = custtable.accountnum 
WHERE salestable.dataareaid = custtable.dataareaid

これらの実行計画を提供します

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


私は同意します。最初のフォームは読みやすいので、それらが等しいことは安心です。今後このフォームのみを使用します。
エリックバーグシュテット

私は私の答えを編集した@ErikBergstedtあなたが実行計画を見ると、あなたはかなり簡単に独自のデータセットとテーブル構造のためにこれを確認することができるはず
チームモニカ-トムV

はい、しました。ありがとうございました。既存の答えが見つからなかったので、私は2番目の意見を探していました。
エリックバーグシュテット

注:の場合、それらは等しいだけINNER JOINです。投げた場合OUTER JOIN、それらは明らかに同じではありません。
ケネスフィッシャー

22

それらは意味的に同一であり、オプティマイザーはこの事実を認識して同一の計画を生成するのに問題はないはずです。

私は両方のテーブルをON参照する条件とを1つのテーブルのみを参照する条件を配置する傾向がありますWHERE

以下のためOUTER JOINSの条件を移動しかしセマンティクスに影響を与えることができます。


7

単純な場合、同じになります。ただし、いくつかの結合を使用する非常に複雑なクエリでは、プランが大幅に異なることがわかりました。私が取り組んでいた最近のものは、約20の異なるテーブルに結合された600万近くの行を持つテーブルから始まりました。このテーブルへの最初の結合のみが内部結合であり、他のすべては左外部結合でした。where句のフィルターは、次のようにパラメーター化されました。

WHERE table1.begindate >= @startdate AND table1.enddate < @enddate 

このフィルターは、計画の前ではなく後で使用されました。これらの条件を最初の内部結合に移行すると、結果セットを制限するために計画の早い段階でフィルターが適用され、CPUと経過時間が約310%減少したため、計画が劇的に変更されました。そのため、多くのSQL Serverの質問と同様に、状況によって異なります。


2
あなたの答えが他のすべてと矛盾しているように見えるので、あなたはより多くの詳細-おそらく実行計画図のスクリーンショットを追加できますか?
ケニーエビット

2
計画はオプティマイザーのタイムアウトを示しましたか?
マーティンスミス

CPU負荷を100%以上減らすにはどうすればよいですか?
マイケルグリーン

2

一般に、フィルターを配置する場所によって違いが生じます。
トムVは、オプティマイザーはクエリが同じであることを認識し、同じ計画を立てると言いますが、それは必ずしも真実ではありません。使用しているSQLのバージョン、クエリの複雑さ、およびオプティマイザがクエリを決定するバッチ全体にとって重要度によって異なります。

最適化プログラムは、バッチのこの部分は、最適な計画を立てるのに十分な時間を費やす価値がないと判断する場合があります。一般に、クエリが処理する必要があるデータ量を減らす条件をWHERE句ではなくON句に入れると、パフォーマンスが向上します(可能であれば、外部結合でこれを行うとデカルト積になります) )

時折のSQL DeveloperがWHERE句のフィルターを見つけるのは少し簡単ですが、ON句のフィルターを使用すると実行時間が数時間短縮される大きなテーブルで作業しました。

したがって、句がクエリが読み取る行数を大幅に削減する可能性がある場合、オプティマイザがより適切なプランを選択できるように、常にON句に入れます。


1

通常の状況では、フィルター条件はWHERE句またはJOIN句で指定できます。OUTER JOIN優先順位に影響を与えない限り(以下を参照)、またはフィルターがそのテーブルに非常に固有な場合(たとえば、テーブルの行の特定のサブセットを指定するTYPE = 12)、フィルターをWHEREの下に配置する傾向があります。

一方、ON句とWHERE句の両方を使用して、結合条件を指定できます(フィルター条件とは対照的)。INNER結合のみを使用している限り、通常の状況でどちらを使用するかは関係ありません。

ただし、外部結合を使用している場合は、大きな違いが生じる可能性があります。たとえば、2つのテーブル(t1とt2)の間にOUTER JOINを指定してから、WHERE句でテーブル間のeqijoin関係を指定する場合(例:t1.col = t2.col)、外部結合を内部結合に変換しました!これは、ON句を使用せずにWHEREを使用して等価結合(またはバージョンによっては非推奨の* =構文を使用してOUTER結合)を指定でき、WHEREがテーブル間の内部等価結合を示す場合、OUTERをオーバーライドするためですJOIN(存在する場合)。

元々の質問はフィルターに関するものでした。結合の種類は問題にならないことが多いのですが、結合はフィルターとしても機能し、そのような状況では結合条件の配置が重要になります。


-1

INNER JOINでは、スタイルの問題です。

ただし、OUTER JOINを使用するとさらに興味深いものになります。ON句とWHERE句の両方でOUTER JOINと条件を使用したクエリの違いを調べる必要があります。結果セットは常に同じではありません。たとえば、

OUTER JOIN dbo.x ON a.ID = x.ID ... WHERE x.SomeField IS NOT NULL

と同じ

INNER JOIN dbo.x ON a.ID = x.ID AND x.SomeField IS NOT NULL

8
結果が異なる場合(もちろん)、パフォーマンスを比較するポイントは何ですか?
ypercubeᵀᴹ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.