最適化しようとしている適度に複雑なクエリの場合、TOP n
句を削除すると実行プランが変わることに気付きました。クエリにTOP n
が含まれる場合、データベースエンジンはTOP
句を無視してクエリを実行し、最後に結果セットをn要求された行数。グラフィカルな実行計画は、これが事実であることを示しているようです-TOP
は「最後の」ステップです。しかし、さらに進んでいるようです。
私の質問は、TOP n句がクエリの実行プランにどのように(そしてなぜ)影響するかです
これが私の場合に起こっていることの簡単なバージョンです:
クエリは、2つのテーブルAとBの行を照合しています。
TOP
句がない場合、オプティマイザは、テーブルAから19k行、テーブルBから46k行と推定します。返される行の実際の数は、Aの場合は16k、Bの場合は13kです。結合にハッシュ一致が使用されますこれら2つの結果セットは合計69行になります(その後、並べ替えが適用されます)。このクエリは非常に迅速に発生します。
TOP 1001
を追加すると、オプティマイザはハッシュ一致を使用しません。代わりに、最初にテーブルAの結果を並べ替え(同じ見積もり/実際の19k/16k)、テーブルBに対してネストされたループを実行します。テーブルBの推定行数は1になり、奇妙なのはTOP n
は、Bに対する推定実行数(インデックスシーク)に直接影響します-常に2n + 1、または私の場合は2003のようです。 TOP n
を変更すると、この見積もりもそれに応じて変わります。もちろん、これはネストされた結合であるため、実際の実行数は16k(テーブルAの行数)であり、これによりクエリの速度が低下します。
実際のシナリオはもう少し複雑ですが、これは基本的なアイデア/動作を捉えています。両方のテーブルは、インデックスシークを使用して検索されます。これはSQL Server 2008 R2 Enterpriseエディションです。
私は、クエリにTOP nが含まれている場合、データベースエンジンがTOP句を無視してクエリを実行し、最後に結果セットをn行の数に縮小することを推測しました要求した。グラフィカルな実行計画は、これが事実であることを示しているようです-TOPが「最後の」ステップです。しかし、それはまだ進んでいるようです。
上記の言い回しは、クエリがどのように実行されるかについての誤った考え方を持っているのではないかと思います。クエリプランの演算子はstepではありません(前のstepの完全な結果セットが次の結果セットによって評価されます) 。
SQL Serverはパイプライン実行モデルを使用し、各演算子はInit()、GetRowなどのメソッドを公開します()、およびClose()。 GetRow()の名前が示すように、オペレーターは(親オペレーターの要求に応じて)オンデマンドで一度に1行を生成します。これはBooks Online 論理演算子と物理演算子のリファレンス に記載されています。詳細は私のブログの投稿 クエリプランが逆方向に実行される理由 にあります。この一度に1行ずつのモデルは、クエリを実行するための適切な直観を形成する上で不可欠です。
私の質問は、
TOP
n句がクエリの実行プランにどのように(そしてなぜ)影響するかです。
TOP
、セミジョイン、および_FAST n
_ query hint などの一部の論理演算は、クエリオプティマイザーが実行プランの代替案をコストする方法に影響します。基本的な考えは、1つの可能なプラン形状が最初のn行をすべての行を返すように最適化された別のプランよりも速く返す可能性があるということです。
たとえば、インデックス付きのネストされたループ結合は、少数の行を返す最も高速な方法ですが、スキャンを伴うハッシュ結合またはマージ結合は、大きなセットではより効率的です。クエリオプティマイザーがこれらの選択を理由とする方法は、操作の論理ツリーの特定のポイントに Row Goal を設定することです。
行の目標は、クエリプランの代替のコスト方法を変更します。その本質は、オプティマイザは、結果セット全体が必要であるかのように各演算子のコストを計算することから始め、適切なポイントに行の目標を設定し、次に、調査する必要があると予想される行の数を推定して計画ツリーをさかのぼります。行の目標を達成するため。
たとえば、論理TOP(10)
は、論理クエリツリーの特定のポイントに10の行目標を設定します。行の目標に至るまでのオペレーターのコストは、行の目標を達成するために必要な行数を見積もるために変更されます。この計算は複雑になる可能性があるため、 完全に機能する例 と注釈付きの実行プランを使用すると、これらすべてを理解しやすくなります。行の目標は、結合タイプの選択やスキャンよりもシークやルックアップを優先するかどうかに影響を与える可能性があります。その詳細 ここ 。
いつものように、行の目標に基づいて選択された実行プランは、オプティマイザの推論能力とそれに提供される情報の品質の影響を受けます。行の目標を持つすべての計画が、実際には必要な行数をより速く生成するわけではありませんが、原価計算モデルによれば、そうします。
行の目標プランが速くないことが判明した場合、通常は、クエリを変更するか、オプティマイザにより適切な情報を提供して、自然に選択されたプランが最適になるようにする方法があります。どちらのオプションが適切かは、コースの詳細によって異なります。行のゴール機能は一般に非常に効果的です(ただし、並列実行プランで使用するときに注意する バグ があります)。
特定のクエリとプランは、ここでの詳細な分析には適さない場合があります(必要に応じて、実際の実行プランを提供してください)。
TOPを使用すると、オプティマイザーは作業を減らす機会を見つけます。 10行を要求すると、セット全体を消費する必要がない可能性が高くなります。したがって、TOP演算子をさらに右に押すことができます。十分に受信されるまで、次の演算子(右側)から行を要求し続けます。
TOPがないと、クエリはデータを最後に並べ替えます。エンジンが結合によって満たされる行数を事前に知ることができる場合、TOPを左側に配置して、同様の計画を使用することを選択することもできます。しかし、ハッシュマッチを実行する努力が比較的高く、おそらくマージ結合のオプションがない場合、オプティマイザはTOPをさらに右側にフィルタリングすることを好むかもしれません。
テーブルBが照会されると、一度に1つの行がフェッチされます。そのため、推定値は1です。また、その行が50%の時間しか検出されないと想定しています。したがって、それを見つけるには2n + 1のシークが必要になると推測します。