表的 CacheId 列存在自定义统计信息。经过一夜的统计数据更新后:
Statistics for INDEX 'ST_TableName_CacheId'.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Name Updated Rows Rows Sampled Steps Density Average Key Length String Index
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ST_TableName_CacheId Apr 26 2014 2:04AM 121482 121482 6 0 4 NO 121482
All Density Average Length Columns
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0.1666667 4 CacheId
Histogram Steps
RANGE_HI_KEY RANGE_ROWS EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
39968 0 20247 0 1
40058 0 20247 0 1
40062 0 20247 0 1
40066 0 20247 0 1
40069 0 20247 0 1
41033 0 20247 0 1
1) 针对此表中现有数据集的连接性能,其中 CacheId = 41033 表现良好,估计值良好(23622 与 20247 的实际值)。
2) 然后使用 CacheId = 41273 of 20247 行执行插入。
3) 然后,针对这个新插入的数据集的连接显示对 1 行的估计不佳,导致计划错误。
4) 手动更新统计信息(最初使用全扫描)显示一个新的直方图:
Statistics for INDEX 'ST_TableName_CacheId'.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Name Updated Rows Rows Sampled Steps Density Average Key Length String Index
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ST_TableName_CacheId Apr 28 2014 10:41AM 141729 141729 7 0 4 NO 141729
All Density Average Length Columns
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0.1428571 4 CacheId
Histogram Steps
RANGE_HI_KEY RANGE_ROWS EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
39968 0 20247 0 1
40058 0 20247 0 1
40062 0 20247 0 1
40066 0 20247 0 1
40069 0 20247 0 1
41033 0 20247 0 1
41274 0 20247 0 1
5) 为 CacheId = 41274 再次运行相同的连接查询显示完美的估计 (20247) 和良好的性能。
Q1)为什么在数学上原始估计如此糟糕?我的意思是 CacheId 是稀疏的,但不是 20000:1 的比率。
Q2)随着 cacheId 数量的增加,您是否期望新插入数据的估计值自然提高?
Q3)是否有任何方法(gulp,技巧或其他方式)来改进估计(或使其不太确定 1 行)而不必在每次插入新数据集时更新统计信息(例如在更大的 CacheId = 999999)。
以下是表中所有 CacheId 的真实行数:
CacheId Rows
39968 20247
40058 20247
40062 20247
40066 20247
40069 20247
41033 20247
41274 20247
[我认为不需要 QP 来回答这个问题,并且需要一些工作来清理它们。如果需要,我可以回答具体问题!]
这是触发自动更新SQL Server 中的统计信息维护功能 (autostats)的规则:
即使 KB 指向 2000 年,到 2012 年仍然如此。
运行这个场景,自己看看。
步骤1
现在我们有一个 ID 为 1 到 6 的表,每个 ID 有 20247 行。到目前为止的统计数据看起来不错!
第2步
看表格和直方图!实际表的 ID = 7 有 20247 行,但直方图不知道您刚刚插入了新数据,因为没有触发自动更新。根据您需要插入 (20247 * 6) * 0.2 + 500 = 24,796.4 行的公式来触发此表上统计信息的自动更新。
因此,如果您查看这些查询的计划,您会看到错误的估计:
查询 #1:
查询 #2:
Optimize 不能说 0 行,所以它只显示 1。
步骤#3
现在直方图显示了缺失的 ID 7,执行计划也显示了正确的估计。
查询 #1:
查询 #2:
是的,只要您从总行数中超过 20% + 500 的阈值。将触发自动更新。您可以通过重新运行 STEP#1 来运行此方案,然后通过运行以下查询来修改 STEP#2:
还没有更新,因为阈值是 24,796.4 - 20247 = 4549.4 但我们只为 ID 8 插入了 4548 行。现在插入这一行并仔细检查直方图:
控制 SQL Server 中的 Autostat (AUTO_UPDATE_STATISTICS) 行为
希望这有助于您理解!很好的问题!
Q3的一个答案)
在连接中,使用 IsNull() 添加一些混淆,最后添加“优化”。
两者似乎都需要。Id 0 并不真正存在。“优化”中使用的 ID 值似乎无关紧要,显然甚至不需要存在。
旁注:我还尝试删除自定义统计信息,在 CacheId 上添加新索引,但就更新行计数阈值而言,其隐式统计信息最终仍与显式自定义统计信息表现相同。
编辑 2014-04-29:
SQL Server 2014 改进的基数估计器中的“升序键”估计值可能已经得到改进
Mark Storey-Smith评论自 2005 SP1 以来还有一个用于升序键的 traceon() 解决方案。
编辑 2015-05-07:
有些案例仍在估计 1 行(有时)。使用 unknown 似乎有帮助,然后 IsNull() 也可以删除: