使用声明的变量时估计行非常错误

pok*_*oke 3 performance sql-server execution-plan sql-server-2014 cardinality-estimates query-performance

我正在非常非常错误的估计聚集索引寻求此查询的步骤(估计行是8637530;实际为74723):

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;
Run Code Online (Sandbox Code Playgroud)

如果我对这样的日期使用字符串文字,则估计值几乎是完美的(估计行数为 75,337.4;实际为 74,723):

select Sum(Quantity)
from Daily_GC_Items
where SalesDate between '10/1/2014' and '10/2/2014'
Run Code Online (Sandbox Code Playgroud)

表定义:

[SalesDate] [date] NOT NULL,
[Store] [varchar](10) NOT NULL,
[GuestCheckNumber] [smallint] NOT NULL,
[ItemSequence] [smallint] NOT NULL,
[Quantity] [smallint] NOT NULL,
(Several more columns)
Run Code Online (Sandbox Code Playgroud)

首要的关键:

[SalesDate] ASC,
[Store] ASC,
[GuestCheckNumber] ASC,
[ItemSequence] ASC
Run Code Online (Sandbox Code Playgroud)

这种行为的可能原因是什么?

Pau*_*ite 13

...SSMS 没有使用 sp_execute 运行它,所以我认为这不是由参数嗅探引起的。这种行为的可能原因是什么?

优化器无法“嗅探”局部变量的值,因此基数估计基于猜测。如果您使用原始基数估计器,则固定猜测为BETWEEN表基数的 9%。

如果使用新的基数估计器,则使用指数退避计算猜测,应用于分离>=<=比较BETWEEN的简写。对于猜测>=<=为30%(0.3)每个,所以整体的猜测是0.3 * SQRT(0.3) = 0.164317 (* table cardinality)

您必须决定是为所有未来的变量值缓存和重用合理的计划,还是在每次执行时重新编译以每次为特定值生成新计划。第二个选项使用参数嵌入优化,它仅在您使用查询提示时应用OPTION (RECOMPILE)。这里有一个明显的权衡,在每次重新编译的成本(结果计划永远不会被缓存以供重用)和为每次执行使用一个不太理想的重用计划之间。

还有其他选项供您考虑,包括在OPTIMIZE FOR提示中指定典型值;有关详细信息,请参阅我的SQLPerformance.com 文章