web-dev-qa-db-ja.com

宣言された変数を使用すると、推定行が非常に間違っている

veryveryこのクエリのクラスター化されたインデックスシークステップの推定値が間違っています(推定行は8,637,530、実際は74,723):

Declare @StartDate as date = '10/1/2014';
Declare @EndDate as date = '10/2/2014';

select Sum(Quantity)
from Daily_GC_Items
where SalesDate between @StartDate and @EndDate;

このような日付に文字列リテラルを使用すると、見積もりはほぼ完璧になります(見積もり行は75,337.4、実際は74,723)。

select Sum(Quantity)
from Daily_GC_Items
where SalesDate between '10/1/2014' and '10/2/2014'

テーブル定義:

[SalesDate] [date] NOT NULL,
[Store] [varchar](10) NOT NULL,
[GuestCheckNumber] [smallint] NOT NULL,
[ItemSequence] [smallint] NOT NULL,
[Quantity] [smallint] NOT NULL,
(Several more columns)

主キー:

[SalesDate] ASC,
[Store] ASC,
[GuestCheckNumber] ASC,
[ItemSequence] ASC

この動作の考えられる原因は何ですか?

3
poke

... SSMSはsp_executeを使用してこれを実行していないため、これはパラメータスニッフィングが原因ではないと思います。この動作の考えられる原因は何ですか?

オプティマイザ ローカル変数の値を「スニッフィング」できません であるため、カーディナリティの推定値はguessに基づいています。元のカーディナリティ推定量を使用している場合、BETWEENの固定推定値はテーブルのカーディナリティの9%です。

新しい カーディナリティ推定量 を使用する場合、推測は 指数バックオフ を使用して計算され、BETWEENの省略形である個別の>=<=の比較に適用されます。 >=<=の推測はそれぞれ30%(0.3)であるため、全体的な推測は0.3 * SQRT(0.3) = 0.164317 (* table cardinality)です。

将来のすべての変数値に対して 妥当な計画をキャッシュして再利用する か、実行ごとに再コンパイルして特定の値の新しい計画を毎回生成するかを決定する必要があります。 2番目のオプションは、 Parameter Embedding Optimization を使用します。これは、クエリヒントOPTION (RECOMPILE)を使用する場合にのみ適用されます。毎回再コンパイルするコスト(結果のプランが再利用のためにキャッシュされることはありません)と、実行ごとに最適ではない再利用プランを使用することの間には、明らかなトレードオフがあります。

OPTIMIZE FORヒントで一般的な値を指定するなど、考慮すべき追加のオプションがあります。詳細については、私の SQLPerformance.comの記事 を参照してください。

13
Paul White 9