web-dev-qa-db-ja.com

IN句により、実行プランがネストされたループからハッシュ一致に変更されます

クエリを調整していて、はっきりしない動作を発見しました。

WHERE IN句を削除すると、クエリは3分ではなく3秒で実行されます。

IN句には7つの項目しかないため、結果には7つの行しか返されません。

これは少し奇妙だと思って、クエリの両方の部分を個別に動作させようとしましたが、何を試してもIN句を使用すると実行時間が長くなります。

実行プランを見ると、いくつかの結合が行われ、それらがNested LoopsからHash Matchに変換されていることがわかります。

SQLをさいの目に切ったので、単一のSELECTViewCTE、およびSELECTに分割されました。 IN句がView内で起こっていることに影響を与えないと思っていたのですが、実際はそうです。

実行プランは次のとおりです。 IN句あり および IN句なし 。クエリの品質については優しくしてください。これは継承されたプロジェクトで進行中の作業であり、私は決して適切なDBAではありません。

Viewから180万行すべてを選択するには、最大1分かかります。 CTEを単独で実行するには、最大3秒かかります。完全なクエリの実行には約3分かかります。

IN句を追加するときに、Nested Loopsに切り替えるのではなく、Hash Match結合を維持するようにSQLServerを説得するにはどうすればよいですか?それとも私が試みるべき他の何かがありますか?

2
nosilleg

OPTION(LOOP JOIN)を使用してネストされたループを強制することはできますが、OPTION(LOOP JOIN、MERGE JOIN)を使用することをお勧めします。これは、オプティマイザーに対してではなく、オプティマイザーで機能し、そうでない限り、必要なことを実行すると言っています。ハッシュマッチ。

しかし、私ももう少し深く掘り下げます。 IN句を使用すると、SQLが単一のテーブルスキャンではなく複数のインデックススキャンを実行している可能性があるため、代わりにWITH(INDEX(0))を使用する必要がある場合があります。

バッチの先頭にSETSTATISTICS IOを追加し、IN句がある場合とない場合で実行し、それぞれの物理的および論理的読み取りの数と、先読みを確認する場合読む、これは私の理論を証明または反証します。

3
Pete Carter

インデックスを付ける:(HasAnswered, AnIDColumn)適切な基になるテーブルから、参照する他の列を含めます。

おそらく、CTE内のAnIDColumnでグループ化するつもりでした。したがって、より適切なインデックス作成オプションがないと、最初にすべての集計を計算してから、それらをフィルタリングする可能性があります。 AnIDColumnのフィルターを最初に実行するように説得する必要があります。これは、理想的なインデックスを追加することによって行うのが最適です。

クエリに何も表示されない場合、結合について質問しています。質問が不完全であるというコメントは正しいです。

2
Rob Farley