クエリを調整していて、はっきりしない動作を発見しました。
WHERE IN
句を削除すると、クエリは3分ではなく3秒で実行されます。
IN
句には7つの項目しかないため、結果には7つの行しか返されません。
これは少し奇妙だと思って、クエリの両方の部分を個別に動作させようとしましたが、何を試してもIN
句を使用すると実行時間が長くなります。
実行プランを見ると、いくつかの結合が行われ、それらがNested Loops
からHash Match
に変換されていることがわかります。
SQLをさいの目に切ったので、単一のSELECT
がView
、CTE
、およびSELECT
に分割されました。 IN
句がView
内で起こっていることに影響を与えないと思っていたのですが、実際はそうです。
実行プランは次のとおりです。 IN
句あり および IN
句なし 。クエリの品質については優しくしてください。これは継承されたプロジェクトで進行中の作業であり、私は決して適切なDBAではありません。
View
から180万行すべてを選択するには、最大1分かかります。 CTE
を単独で実行するには、最大3秒かかります。完全なクエリの実行には約3分かかります。
IN
句を追加するときに、Nested Loops
に切り替えるのではなく、Hash Match
結合を維持するようにSQLServerを説得するにはどうすればよいですか?それとも私が試みるべき他の何かがありますか?
OPTION(LOOP JOIN)を使用してネストされたループを強制することはできますが、OPTION(LOOP JOIN、MERGE JOIN)を使用することをお勧めします。これは、オプティマイザーに対してではなく、オプティマイザーで機能し、そうでない限り、必要なことを実行すると言っています。ハッシュマッチ。
しかし、私ももう少し深く掘り下げます。 IN句を使用すると、SQLが単一のテーブルスキャンではなく複数のインデックススキャンを実行している可能性があるため、代わりにWITH(INDEX(0))を使用する必要がある場合があります。
バッチの先頭にSETSTATISTICS IOを追加し、IN句がある場合とない場合で実行し、それぞれの物理的および論理的読み取りの数と、先読みを確認する場合読む、これは私の理論を証明または反証します。
インデックスを付ける:(HasAnswered, AnIDColumn)
適切な基になるテーブルから、参照する他の列を含めます。
おそらく、CTE内のAnIDColumnでグループ化するつもりでした。したがって、より適切なインデックス作成オプションがないと、最初にすべての集計を計算してから、それらをフィルタリングする可能性があります。 AnIDColumnのフィルターを最初に実行するように説得する必要があります。これは、理想的なインデックスを追加することによって行うのが最適です。
クエリに何も表示されない場合、結合について質問しています。質問が不完全であるというコメントは正しいです。