33

バックグラウンド

合計クエリを実行して実験しているときに、推定プランに「フェッチクエリ」が表示されることがあることに気付きました

フェッチ

実際の計画では、クラスター化されたインデックス スキャンからのフェッチが繰り返されていることが示されています。

フェッチスキャン

他の場合 (TOPクエリに a を追加する場合など) には、見積もられた計画に、作業テーブルにデータを入力する "Population Query" ステージが表示されます。

フェッチして入力

実際の計画では、クラスター化されたインデックス スキャンを示して作業テーブルにデータを入力し、その作業テーブルに対してシークを繰り返します。

シーク

質問

  1. あるアプローチを他のアプローチよりも選択する際に、SQL Server はどのような基準を使用しますか?
  2. 最初の方法 (追加の作業テーブル作成ステップなし) がより効率的であると考えるのは正しいでしょうか?

(おまけの質問: 最初のクエリの各スキャンが 2 つの論理読み取りとしてカウントされる理由を誰かが説明できれば、これも非常に啓発的なものになる可能性があります)

追加情報

カーソルが動的プランまたは静的プランのいずれかを使用できることを説明するこの記事を見つけました。FAST_FORWARDこの場合の最初のクエリは動的プランを使用しており、2 番目のクエリは静的プランを使用しているようです。

また、試してみると

SET @C2 = CURSOR DYNAMIC TYPE_WARNING FOR SELECT TOP ...

カーソルは暗黙的にカーソルに変換されるkeysetため、おそらくルーベンの回答の理由により、構造が動的カーソルに対してサポートされていないことは明らかですTOP-これについての決定的な説明をまだ探しています。

ただし、動的カーソルは静的カーソル ( source 1source 2 ) よりも遅くなる傾向があることも読みました。これは、静的な種類がソースデータを読み取り、コピーしてからコピーを読み取る必要があることを考えると、驚くべきことのように思えます。ソースデータを読み取ります。前に参照した記事では、動的カーソルが. 誰でもこれらが何であるか説明できますか? それは単なる RID か CI キーか、それとも別のものですか?markers

脚本

SET STATISTICS IO OFF

CREATE TABLE #T ( ord INT IDENTITY PRIMARY KEY, total INT, Filler char(8000))

INSERT INTO #T (total) VALUES (37),(80),(55),(31),(53)

DECLARE @running_total INT, 
    @ord INT, 
    @total INT
    
SET @running_total = 0
SET STATISTICS IO ON
DECLARE @C1 AS CURSOR;
SET @C1 = CURSOR FAST_FORWARD FOR SELECT ord, total FROM #T ORDER BY ord;
OPEN @C1;
PRINT 'Initial FETCH C1'
FETCH NEXT FROM @C1 INTO @ord, @total ;
WHILE @@FETCH_STATUS = 0
BEGIN
  SET @running_total = @running_total + @total
  PRINT 'FETCH C1'
  FETCH NEXT FROM @C1 INTO @ord, @total ;
END

SET @running_total = 0
SET STATISTICS IO ON
DECLARE @C2 AS CURSOR;
SET @C2 = CURSOR FAST_FORWARD FOR SELECT TOP 5 ord, total FROM #T ORDER BY ord;
OPEN @C2;
PRINT 'Initial FETCH C2'
FETCH NEXT FROM @C2 INTO @ord, @total ;
WHILE @@FETCH_STATUS = 0
BEGIN
  SET @running_total = @running_total + @total
  PRINT 'FETCH C2'
  FETCH NEXT FROM @C2 INTO @ord, @total ;
END

PRINT 'End C2'
DROP TABLE #T 
4

2 に答える 2

9

単なる推測ですが、通常、TOP-ORDER BY では、SQL Server が何らかの方法で結果をバッファリングする必要があります (インデックス スキャンの結果、または一時構造内の実際の結果全体、またはその中間のいずれか)。

対応する SELECT が正確に 5 行 (または最悪: カーソルは 5 行以上を返します)。

この奇妙な状況は、理論的には、インデックス スキャンの範囲がカーソルに対して既に決定された後にテーブルに削除または挿入があり、挿入/削除がインデックス スキャンの範囲内にあるが、まだフェッチが完了していない場合に発生する可能性があります。これが起こらないようにするために、彼らはここで安全側に誤りを犯すかもしれません. (そして、#temp テーブル用に最適化しませんでした。)

質問ですが、SQL Server では句FETCH FROM SELECT TOP nなしでa を使用できますか? ORDER BY(ここでは SQL Server インスタンスを実行していません。) それがどのような計画を引き起こしているのかを知ることは興味深いかもしれません。

于 2011-10-26T00:52:14.990 に答える
5

あるアプローチを他のアプローチよりも選択する際に、SQL Server はどのような基準を使用しますか?

これは主にコストベースの決定です。リンク先の記事から引用すると、「動的計画が有望に見える状況では、コスト比較がヒューリスティックにスキップされる可能性があります。これは主に非常に安価なクエリで発生しますが、詳細は難解です。」

最初の方法 (追加の作業テーブル作成ステップなし) がより効率的であると考えるのは正しいでしょうか?

場合によります。動的カーソル プランと静的カーソル プランには、それぞれ長所と短所があります。最終的にすべての行が変更される場合、静的プランのパフォーマンスが向上する可能性があります。これについては後ほど詳しく説明します。

TOP構造が動的カーソルに対してサポートされていないことは明らかです

これは本当です。動的カーソル プラン内のすべてのイテレータは、状態の保存と復元、順方向および逆方向のスキャン、出力行ごとに 1 つの入力行の処理、非ブロック化が可能である必要があります。一般に、Top はこれらすべての要件を満たしているわけではありません。このクラスは、必要な、 およびメソッドを (特に)CQScanTopNew実装していません。Set/Get/Goto/Marker()ReverseDirection()

また、動的カーソルは静的カーソルよりも遅くなる傾向があることも読みました。

これは、ほとんどまたはすべてのカーソル セットがタッチされる Transact-SQL カーソルの場合に当てはまります。動的クエリ プランの状態の保存と復元にはコストがかかります。各呼び出しで 1 つの行が処理され、最終的にすべての行が処理される場合、この保存/復元のオーバーヘッドは最大化されます。

静的カーソルには、セットのコピーを作成するオーバーヘッドがありますが (大規模なセットではこれが支配的な要因になる場合があります)、取得の行ごとのコストは非常に小さくなります。キーセットは、ソース テーブルに外部結合して非キー列を取得する必要があるため、静的よりも行ごとの取得オーバーヘッドが高くなります。

動的カーソルは、セットの比較的小さな部分がアクセスされる場合、および/または検索が一度に行単位ではない場合に最適です。これは、多くの一般的なカーソル シナリオでの典型的なアクセス パターンですが、ブログ投稿がテストする傾向があるものとは異なります :)

最初のクエリの各スキャンが2つの論理読み取りとしてカウントされる理由を誰かが説明できれば、それも非常に啓発的かもしれません

これは、スキャンのために状態を保存する方法と、読み取りをカウントする方法に依存します。

前に参照した記事では、動的カーソルはマーカーを使用すると述べています。誰でもこれらが何であるか説明できますか? それは単なる RID か CI キーか、それとも別のものですか?

マーカーは、アクセス メソッドだけでなく、動的カーソル プランの各イテレータに存在します。「マーカー」は、計画反復子を中断した時点から再開するために必要なすべての状態情報です。アクセス方法の場合、RID またはインデックス キー (必要に応じて一意化子を使用) が重要な部分を占めますが、すべてではありません。

于 2014-11-21T13:06:57.540 に答える