SQL Server 2014 COUNT(DISTINCT x) 忽略列 x 的统计密度向量

Geo*_*son 16 sql-server sql-server-2014 cardinality-estimates

对于一个COUNT(DISTINCT)具有约 10 亿个不同值的查询计划,我得到了一个散列聚合估计只有约 300 万行的查询计划。

为什么会这样?SQL Server 2012 产生了很好的估计,所以这是我应该在 Connect 上报告的 SQL Server 2014 中的错误吗?

查询和差估计

-- Actual rows: 1,011,719,166
-- SQL 2012 estimated rows: 1,079,130,000 (106% of actual)
-- SQL 2014 estimated rows: 2,980,240 (0.29% of actual)
SELECT COUNT(DISTINCT factCol5)
FROM BigFactTable
OPTION (RECOMPILE, QUERYTRACEON 9481) -- Include this line to use SQL 2012 CE

-- Stats for the factCol5 column show that there are ~1 billion distinct values
-- This is a good estimate, and it appears to be what the SQL 2012 CE uses
DBCC SHOW_STATISTICS (BigFactTable, _WA_Sys_00000005_24927208)
--All density   Average Length  Columns
--9.266754E-10  8               factCol5
SELECT 1 / 9.266754E-10
-- 1079126520.46229
Run Code Online (Sandbox Code Playgroud)

查询计划

在此处输入图片说明

完整脚本

这是使用仅统计数据库的情况的完整再现

到目前为止我尝试过的

我深入研究了相关列的统计数据,发现密度向量显示了大约 11 亿个不同的值。SQL Server 2012 使用此估计并生成一个很好的计划。令人惊讶的是,SQL Server 2014 似乎忽略了统计数据提供的非常准确的估计值,而是使用了一个低得多的估计值。这会产生一个慢得多的计划,它没有保留几乎足够的内存并溢出到 tempdb。

我尝试了 trace flag 4199,但这并没有解决问题。最后,我尝试通过跟踪标志的组合来挖掘优化器信息(3604, 8606, 8607, 8608, 8612),如本文后半部分所示。但是,在它出现在最终输出树中之前,我无法看到任何解释错误估计的信息。

连接问题

根据对这个问题的回答,我也在Connect 中将此作为问题提交

Pau*_*ite 15

基数估计的推导方式对我来说肯定是违反直觉的。非重复计数计算(可通过扩展事件或跟踪标志 2363 和 3604 查看)是:

统计推导

注意帽子。这的一般逻辑似乎非常合理(不能有更多不同的值),但上限是从采样的多列统计信息中应用的:

DBCC SHOW_STATISTICS 
    (BigFactTable, [PK_BigFactTable])
WITH
    STAT_HEADER, 
    DENSITY_VECTOR;
Run Code Online (Sandbox Code Playgroud)

PK数据

这显示了从 3,439,431,721 行中采样的 2,980,235 行,其 Col5 级别的密度向量为 3.35544E-07。它的倒数给出了许多不同的值,即 2,980,235,使用真实数学四舍五入为 2,980,240。

现在的问题是,给定抽样统计数据,模型应该对不同值的数量做出哪些假设。我希望它可以推断,但这并没有完成,也许是故意的。

更直观地,我希望它不会使用多列统计信息,而是查看 Col5 上的密度(但它没有):

DBCC SHOW_STATISTICS 
    (BigFactTable, [_WA_Sys_00000005_24927208])
WITH
    STAT_HEADER, 
    DENSITY_VECTOR;
Run Code Online (Sandbox Code Playgroud)

Col5 统计数据

这里的密度是9.266754E-10,倒数其中是1079126528

与此同时,一种明显的解决方法是使用完整扫描更新多列统计信息。另一种是使用原始基数估计器。

您打开的 Connect 项,SQL 2014 采样的多列统计信息覆盖了非前导列的更准确的单列统计信息,对于 SQL Server 2017标记为固定