TOPは実行計画にどのように(そしてなぜ)影響しますか?


35

最適化しようとしている中程度に複雑なクエリのTOP n場合、句を削除すると実行プランが変更されることに気付きました。クエリにTOP nデータベースエンジンが含まれている場合、TOP句を無視してクエリを実行し、最後にその結果セットを要求されたn行まで縮小するだけだと思いました。グラフィカルな実行計画は、これが事実であることを示しているようです- TOP「最後の」ステップです。しかし、さらに進んでいるようです。

私の質問は、TOP n句がクエリの実行計画にどのように(そしてなぜ)影響するかです。

これは私の場合に起こっていることの単純化されたバージョンです:

クエリは、AとBの2つのテーブルの行を照合しています。

TOP句がない場合、オプティマイザは、テーブルAから19k行、テーブルBから46k行があると推定します。返される実際の行数は、Aで16k、Bで13kです。合計69行(ソートが適用されます)。このクエリは非常に高速に発生します。

TOP 1001オプティマイザーを追加するとき、ハッシュ一致を使用しません。代わりに、最初にテーブルAからの結果をソートし(同じ推定値/実際の19k / 16k)、テーブルBに対してネストされたループを実行します。テーブルBの推定行数は1になり、奇妙なことはTOP n、 Bに対する推定実行数(インデックスシーク)-常に2n + 1、または私の場合は2003であるように見えますTOP n。もちろん、これはネストされた結合であるため、実際の実行回数は16k(テーブルAの行数)であり、これによりクエリの速度が低下します。

実際のシナリオはもう少し複雑ですが、これは基本的なアイデア/動作をキャプチャします。両方のテーブルは、インデックスシークを使用して検索されます。これはSQL Server 2008 R2 Enterpriseエディションです。


クエリにはORDER BY句があります。追加TOP( -私は知らない、もちろん2が関連している可能性があり)...このソートが発生した計画の変更を、私はより多くのそれは、インデックスの実行回数がテーブルBに対して求めてどのように影響するかが心配です
デビッド

1
関連する議論:FAST num_rowsクエリヒント。
レムスルサヌ

回答:


39

クエリにTOP nが含まれている場合、データベースエンジンはTOP句を無視してクエリを実行し、最後にその結果セットを要求されたn行まで縮小するだけだと思います。グラフィカルな実行計画は、これが事実であることを示しているようです-TOPは「最後の」ステップです。しかし、さらに進んでいるようです。

上記の言い回しは、クエリの実行方法について誤ったメンタルピクチャを持っているかもしれないと思います。クエリプランの演算子はステップではありません(前のステップの完全な結果セットが次のステップによって評価されます)。

SQL Serverはパイプライン実行モデルを使用します。各モデルは、Init()GetRow()Close()などのメソッドを公開します。関連項目GetRow()名前が示唆している(親オペレータによって要求されるように)、オペレータは、必要に応じて一度に1行を生成します。これは、Books Onlineの論理演算子と物理演算子のリファレンスに記載されています。詳細については、ブログ投稿「クエリプランが後方に実行される理由」を参照してください。この行単位のモデルは、クエリ実行の健全な直感を形成するために不可欠です。

私の質問は、TOPn句がクエリの実行計画にどのように(そしてなぜ)影響するかです。

TOPFAST n セミジョインクエリヒントなどの一部の論理演算は、クエリオプティマイザーの実行プランの代替コストに影響します。基本的な考え方は、1つの可能なプラン形状が、すべての行を返すように最適化された別のプランよりも早く最初のn行を返す可能性があるということです。

たとえば、インデックス付きのネストされたループ結合は、多くの場合、少数の行を返すための最速の方法ですが、スキャンを使用したハッシュ結合またはマージ結合は、大きなセットではより効率的です。クエリオプティマイザーがこれらの選択について判断する方法は、操作の論理ツリーの特定のポイントに行目標を設定することです。

行の目標は、クエリプランの代替案のコストを変更します。その本質は、オプティマイザーは、完全な結果セットが必要であるかのように各演算子をコスト計算することから開始し、適切なポイントで行の目標を設定し、計画ツリーをさかのぼって調査する必要があると予想される行の数を推定することです行の目標を達成するために。

たとえばTOP(10)、論理クエリツリーの特定のポイントで10の行ゴールを設定します。行の目標に至るまでの演算子のコストは、行の目標を満たすために生成する必要がある行の数を見積もるために変更されます。この計算は複雑になる可能性があるため、完全に機能する例と注釈付きの実行計画を使用すると、このすべてを理解しやすくなります。行の目標は、結合タイプの選択や、検索よりもシークとルックアップの選択に影響を与える可能性があります。詳細はこちら

いつものように、行の目標に基づいて選択された実行計画は、オプティマイザーの推論能力とそれに提供される情報の品質の影響を受けます。行目標を持つすべての計画が実際に必要な行数をより速く生成するわけではありませんが、原価計算モデルによるとそうなります。

行のゴールプランが速くないことが判明した場合、通常、クエリを変更する方法や、自然に選択されたプランが最適になるようにオプティマイザに適切な情報を提供する方法があります。どのオプションがあなたの場合に適切であるかは、もちろん詳細に依存します。行目標機能は一般に非常に効果的です(ただし、並列実行プランで使用する場合には注意すべきバグがあります)。

特定のクエリと計画は、ここでの詳細な分析には適さない可能性があります(必要に応じて、実際の実行計画を必ず提供します)。


12

TOPを使用すると、オプティマイザーは作業を減らす機会を見つけます。10行を要求すると、セット全体を消費する必要がない可能性が高くなります。したがって、TOP演算子をさらに右に押すことができます。十分に受信するまで、次の演算子(右側)から行を要求し続けます。

TOPがなければ、クエリは最後にデータをソートします。エンジンが結合によって満たされる行数を事前に知ることができた場合、左にTOPを配置して同様のプランを使用することを選択できます。しかし、比較的高いハッシュマッチを実行するための努力と、おそらくマージ結合のオプションがないため、オプティマイザーは、TOPをさらに右にフィルター処理することを好む場合があります。

テーブルBを照会すると、一度に1つの行がフェッチされます。そのため、推定値は1です。また、その行は常に50%しか検出されないと想定しています。したがって、それを見つけるには2n + 1回のシークが必要だと推測します。


データのフェッチ方法に基づいて行の推定数が変わることは正しくないようです。データの取得方法がカーディナリティに影響することはありません。フェッチ方法の変更は、代わりに実行回数に反映されますか?
デビッド

「推定行数」は実行ごとです。ネストされたループでは、複数回実行される可能性が非常に高くなります。
ロブファーリー

これは、実際の行数および(実際の)実行数とは異なる動作になります。実際のプランで16,834回の実際の実行と15,407回の実際の行が返された場合、これは16kシークを実行したが、述語に一致する15kのみが見つかったことを意味します。テーブルよりも約10倍大きい... -それは、実行ごとに15kの行を意味している場合、これは15K * 16K =2.4億行だろう
デヴィッド

また、あなたの答えの最後の声明に従うかどうかはわかりません。2n + 1が「it」を見つけようとすると、「it」とはどういう意味ですか?確かに単一の行ではありませんか?オプティマイザーは、Aの特定の行についてBに一致する可能性が50%あると想定しているため、Bから1001個の一致を取得するためにAから2003行を「試行」する必要があると思いますか?この動作は、Microsoftによって文書化されていますか?そして、それはTOP条項と何の関係がありますか?回答/忍耐に感謝します。
デビッド

はい、推定行は実行ごとです。実際の行は合計です。ただし、同じ行を複数回返す演算子を示すのは非常に簡単なので、演算子がテーブルにあるよりも多くの行を返すことは問題ありません。
ロブファーリー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.