web-dev-qa-db-ja.com

TOP(変数)を使用したソート推定の理解

以下のクエリがあり、変数でTOPを使用した場合のソートの見積もりを理解しようとしています。

[〜#〜]計画[〜#〜]

create table justint ( c1 int )

insert into justint
select top 1000000 row_number() over(order by t1.number) as N
from   master..spt_values t1 
cross join master..spt_values t2

declare  @MaxRowsToReturn    INT     = 500
SELECT  top (@MaxRowsToReturn) c1
FROM justint WITH (NOLOCK)
where  c1 >= 600000
ORDER BY c1 ASC

では、ソート演算子に入る404986の見積もりは、100の見積もりとしてどのように出力されますか? TOP演算子で変数をスニッフィングできないので、それは単なる任意の数ですか?

1
jesijesi

これは、パラメータスニッフィング(またはこの場合はその欠如)の問題のように思われます。

オプティマイザーは、ユーザーがTOPオペレーターから必要とする行数を知らなくても、バッチに最適なプランを選択する必要があります。ここで重要なのは、@ Maxrowstoreturnは、それが使用されるバッチ中に設定されるということです。つまり、エンジンは、その変数が初期化または使用される前に、プラン全体を作成する必要があります。なぜ100という数字が使われるのかというと、とにかくこの状況で確実な見積もりを提供する方法がないので、開発者による恣意的な決定である可能性があります。

次のコードを実行すると、SQLは入力パラメーターを使用してより正確な実行プランを作成できるため、見積もりが修正されます。

create table justint ( c1 int )
go

insert into justint
select top 1000000 row_number() over(order by t1.number) as N
from   master..spt_values t1 
cross join master..spt_values t2
go

update statistics justint with fullscan;
go


create procedure #tmpproc

(@Maxrowstoreturn int)

 AS
begin


SELECT  top (@MaxRowsToReturn) c1
FROM justint WITH (NOLOCK)
--where  c1 >= 600000
ORDER BY c1 ASC
end
go

exec #tmpproc 10000


drop table justint

enter image description here

1
George.Palacios