设定
我在了解基数估算值时遇到了一些麻烦。这是我的测试设置:
- 2010版本的Stack Overflow数据库
- SQL Server 2017 CU15 + GDR(KB4505225)-14.0.3192.2
- 新CE(兼容级别140)
我有这个过程:
USE StackOverflow2010;
GO
CREATE OR ALTER PROCEDURE #sp_PostsByCommentCount
@CommentCount int
AS
BEGIN
SELECT *
FROM dbo.Posts p
WHERE
p.CommentCount = @CommentCount
OPTION (RECOMPILE);
END;
GO
dbo.Posts
表上没有非聚集索引或统计信息(上有聚集索引Id
)。
当要求为此的估计计划时,出来的“估计行” dbo.Posts
为1,934.99:
EXEC #sp_PostsByCommentCount @CommentCount = 51;
当我要求估算的计划时,会自动创建以下统计信息对象:
DBCC SHOW_STATISTICS('dbo.Posts', [_WA_Sys_00000006_0519C6AF]);
其中的重点是:
- 统计数据的抽样率很低,为1.81%(67,796 / 3,744,192)
- 仅使用31个直方图步骤
- “所有密度”值是
0.03030303
(采样了33个不同的值) RANGE_HI_KEY
直方图中的最后一个是50,其中EQ_ROWS
1
题
传递任何大于50的值(直到并包括2,147,483,647),将导致1,934.99行估计。 使用什么计算或值来产生此估计? 顺便说一句,传统基数估计量产生的估计值为1行。
我尝试过的
这里是一些我有的理论,我尝试过的事情,或者是我在研究过程中能够挖掘到的其他信息。
密度矢量
我最初以为它是密度矢量,就好像我曾经使用过一样OPTION (OPTIMIZE FOR UNKNOWN)
。但是此统计对象的密度向量为3,744,192 * 0.03030303 = 113,460,不是这样。
扩展活动
我尝试运行一个扩展事件会话,该会话收集了该query_optimizer_estimate_cardinality
事件(我从Paul White的博客文章Cardinality Estimation:Combining Density Statistics中了解到),并得到了这些有趣的花絮:
<CalculatorList>
<FilterCalculator CalculatorName="CSelCalcColumnInInterval" Selectivity="-1.000"
CalculatorFailed="true" TableName="[p]" ColumnName="CommentCount" />
<FilterCalculator CalculatorName="CSelCalcAscendingKeyFilter" Selectivity="0.001"
TableName="[p]" ColumnName="CommentCount" UseAverageFrequency="true"
StatId="4" />
</CalculatorList>
因此,看来CSelCalcAscendingKeyFilter
计算器已被使用(另一种表示失败,无论如何)。该列不是键,也不是唯一的,或者不是必然升序的,而是任何东西。
谷歌搜索这个词使我有一些博客文章:
这些帖子指示新的CE将这些直方图外部估计基于密度向量和stat的修改计数器的组合。不幸的是,我已经排除了密度矢量(我认为?!),并且修改计数器为零(sys.dm_db_stats_properties
无论如何)。
跟踪标志
Forrest建议我打开TF 2363以获取有关估计过程的更多信息。我认为该输出中最相关的是:
Plan for computation:
CSelCalcAscendingKeyFilter(avg. freq., QCOL: [p].CommentCount)
Selectivity: 0.000516798
这是一个突破(感谢Forrest!):这个0.000516798
数字(似乎已经在Selectivity="0.001"
上面的XE 属性中无助地舍入了)乘以表中的行数即是我一直在寻找的估计值(1,934.99)。
我可能缺少明显的东西,但是我无法对工程师内部如何生成选择值进行反向工程CSelCalcAscendingKeyFilter
。