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つのクエリのどちらがパフォーマンスを向上させるか、そしてその理由は何ですか?それとも同じですか?
パフォーマンスは同じになります。オプティマイザはこれを認識し、同じ計画を作成します。
一方、私はそれらが等しいとは言いません。最初の形式質問内は、はるかに読みやすく、一般に期待されています。
手元にあるいくつかのテーブルを使用した例では、クエリをどのように記述しても、実行プランはまったく同じであることがわかります。
自分のテーブルとデータセットのクエリプランを決定して、状況で何が起きているかを確認できるようにする必要があります。
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
これらの実行計画を提供します
それらは意味的に同一であり、オプティマイザはこの事実を認識して同一の計画を生成するのに問題はないはずです。
両方のテーブルを参照する条件をON
に入れ、WHERE
の1つのテーブルのみを参照する条件を入れる傾向があります。
ために OUTER JOINS
ただし、条件を移動するとセマンティクスに影響を与える可能性があります。
単純なケースでは同じです。ただし、いくつかの結合を持つ非常に複雑なクエリの計画は大きく異なります。私が最近取り組んだものは、約20の異なるテーブルに結合された600万行に近いテーブルから始めました。このテーブルへの最初の結合のみがinner結合であり、他のすべては左外部結合でした。 where句のフィルターは、次のようにパラメーター化されています。
WHERE table1.begindate >= @startdate AND table1.enddate < @enddate
このフィルターは、計画の前半ではなく後半で使用されました。これらの条件を最初の内部結合に移動すると、結果セットを制限するためにフィルターが計画の早い段階で適用され、CPUと経過時間が約310%減少したため、計画は劇的に変化しました。したがって、多くのSQL Serverの質問と同様に、状況によって異なります。
一般に、フィルターを配置する場所によって違いが生じます。
トムVは、オプティマイザーはクエリが同じであり、同じプランを考え出すことを認識すると言いますが、常にそうであるとは限りません。これは、使用しているSQLのバージョン、クエリの複雑さ、およびオプティマイザがクエリを決定するバッチ全体にとってどの程度重要かによって異なります。
オプティマイザーは、バッチのこの部分は、最適な計画を立てるのに十分な時間を費やす価値がないと判断する場合があります。一般に、クエリが処理する必要があるデータの量を減らす条件をWHERE句ではなくON句に置くと、パフォーマンスが向上します(可能な場合、これを外部結合で実行すると、デカルト積が生成されるため。)
時折SQL開発者がWHERE句でフィルターを見つけるのは少し簡単ですが、ON句でフィルターを使用すると実行時間を数時間短縮するいくつかの大きなテーブルで作業しました。
したがって、クエリが読み取る行数を大幅に減らす可能性がある句がある場合、オプティマイザがより適切なプランを選択できるように、常に句をON句に入れます。
通常の状況では、フィルター条件はWHERE句またはJOIN句で指定できます。 OUTER JOINの優先順位が影響を受ける可能性がある場合(以下を参照)またはフィルターがそのテーブルに非常に固有である場合(例:TYPE = 12でテーブル内の行の特定のサブセットを指定する場合)を除き、私はWHEREの下にフィルターを配置する傾向があります。
一方、ON句とWHERE句の両方を使用して、(フィルター条件ではなく)結合条件を指定できます。 INNER結合のみを使用している限り、通常の状況ではどちらを使用しても問題ありません。
ただし、OUTER結合を使用している場合は、大きな違いが生じる可能性があります。たとえば、2つのテーブル(t1とt2)の間にOUTER JOINを指定した後、WHERE句でテーブル間のeqijoin関係を指定すると(たとえば、t1.col = t2.col)、次のようになります。 OUTER結合をINNER結合に変換しました!これは、WHEREを使用して、ON句を使用せずに等結合(またはバージョンによってはOUTER結合で、廃止予定の* =構文を使用)を指定でき、WHEREがテーブル間の内部等結合を示す場合、OUTERをオーバーライドするためですJOIN(存在する場合)。
元々の質問はフィルターに関するものでしたが、結合のタイプは多くの場合問題になりませんが、結合はフィルターとしても機能し、そのような状況では結合条件の配置が重要になる可能性があります。