バックグラウンド
合計クエリを実行して実験しているときに、推定プランに「フェッチクエリ」が表示されることがあることに気付きました
実際の計画では、クラスター化されたインデックス スキャンからのフェッチが繰り返されていることが示されています。
他の場合 (TOP
クエリに a を追加する場合など) には、見積もられた計画に、作業テーブルにデータを入力する "Population Query" ステージが表示されます。
実際の計画では、クラスター化されたインデックス スキャンを示して作業テーブルにデータを入力し、その作業テーブルに対してシークを繰り返します。
質問
- あるアプローチを他のアプローチよりも選択する際に、SQL Server はどのような基準を使用しますか?
- 最初の方法 (追加の作業テーブル作成ステップなし) がより効率的であると考えるのは正しいでしょうか?
(おまけの質問: 最初のクエリの各スキャンが 2 つの論理読み取りとしてカウントされる理由を誰かが説明できれば、これも非常に啓発的なものになる可能性があります)
追加情報
カーソルが動的プランまたは静的プランのいずれかを使用できることを説明するこの記事を見つけました。FAST_FORWARD
この場合の最初のクエリは動的プランを使用しており、2 番目のクエリは静的プランを使用しているようです。
また、試してみると
SET @C2 = CURSOR DYNAMIC TYPE_WARNING FOR SELECT TOP ...
カーソルは暗黙的にカーソルに変換されるkeyset
ため、おそらくルーベンの回答の理由により、構造が動的カーソルに対してサポートされていないことは明らかですTOP
-これについての決定的な説明をまだ探しています。
ただし、動的カーソルは静的カーソル ( source 1、source 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