为啥过滤统计信息被忽略
Posted
技术标签:
【中文标题】为啥过滤统计信息被忽略【英文标题】:Why is Filtered Statistics being ignored为什么过滤统计信息被忽略 【发布时间】:2016-03-18 06:02:34 【问题描述】:我在理解 Cardinality Estimator
如何使用过滤统计信息时遇到了一些问题。
当我在 CE 120
上运行查询时,它会产生预期的估计值,但是当我切换到 CE 70
时,它似乎忽略了过滤后的统计信息。
此外,如果我不使用 WHERE
子句中的实际统计信息列,CE 120
似乎会忽略过滤的统计信息。
以下脚本用于创建和填充测试表以及创建过滤的统计信息。
/*
Microsoft SQL Server 2014 - 12.0.4213.0 (X64)
Jun 9 2015 12:06:16
Copyright (c) Microsoft Corporation
*/
IF OBJECT_ID('Test_FS') IS NOT NULL
DROP TABLE Test_FS;
CREATE TABLE Test_FS (id int identity, a char(2), b char(2), c datetime
CONSTRAINT [Test_FS_pk] PRIMARY KEY CLUSTERED (id ASC))
INSERT INTO Test_FS (a,b,c)
VALUES
('A1', 'B1', '2016-03-01'),
('A1', 'B1', '2016-09-01'),
('A1', 'B2', '2016-09-01'),
('A1', 'B2', '2016-09-01'),
('A1', 'B2', '2016-09-01'),
('A1', 'B2', '2016-09-01'),
('A1', 'B2', '2016-09-01'),
('A1', 'B2', '2016-09-01'),
('A2', 'B1', '2016-09-01'),
('A2', 'B1', '2016-09-01')
CREATE STATISTICS Test_FS_Filter_Stat
ON Test_FS (c)
WHERE a = 'A1'
AND b = 'B1'
WITH FULLSCAN
第一个查询是CE 120
SELECT *
FROM Test_FS
WHERE a = 'A1'
AND b = 'B1'
AND c >= GETDATE()
OPTION(RECOMPILE)
它的行为与预期的一样:估计 1 行 / 实际 1 行
值得注意的是,它不会为个人自动创建统计信息 列
问题 1
当我们使用CE 70
运行它时
SELECT *
FROM Test_FS
WHERE a = 'A1'
AND b = 'B1'
AND c >= GETDATE()
OPTION(RECOMPILE, QUERYTRACEON 9481)
它忽略过滤的统计数据并估计 2.88 行。
请注意,我们现在为各个列自动创建了统计信息
统计名称 _WA_Sys_00000002_3587F3E0 _WA_Sys_00000003_3587F3E0 _WA_Sys_00000004_3587F3E0 Test_FS_Filter_Stat
为什么CE 70
会忽略过滤的统计信息?
我感觉是 GETDATE()
造成的,但我不明白为什么以及可以做些什么。
问题 2
现在使用CE 120
对过滤后的统计信息target
列运行不带条件的查询 - 仅在过滤器列上运行条件。
SELECT *
FROM Test_FS
WHERE a = 'A1'
AND b = 'B1'
OPTION(RECOMPILE)
这次它估计 3.57771 行,实际返回 2。
为什么不使用过滤后的统计数据 - 总行数?
附加信息
我查看了为上述查询加载的统计信息,结果如下:
问题 1: CE 70 在谓词为 '>= GETDATE()' 时忽略过滤统计信息,但在指定 '= GETDATE()' 时使用它。如果指定了日期常数,CE 70 在这两种情况下都使用过滤的统计信息。
CE 120 在上述所有情况下都使用过滤后的统计信息。
问题 2: 当没有在“c”上指定谓词时,两个 CE 都完全忽略了过滤的统计信息,我觉得这很奇怪,因为这肯定会给他们最好的估计。
【问题讨论】:
【参考方案1】:回答你的第一个问题:GETDATE
是非确定性函数:
DECLARE @c DATETIME = GETDATE()
SELECT *
FROM Test_FS
WHERE a = 'A1' AND b = 'B1' AND c >= @c
OPTION(RECOMPILE)
SELECT *
FROM Test_FS
WHERE a = 'A1' AND b = 'B1' AND c >= @c
OPTION(RECOMPILE, QUERYTRACEON 9481)
来自dbForge的执行计划:
【讨论】:
感谢德瓦特。这就是我陷入困境的地方——这就是我发现的:如果我只有一个条件“c >= GETDATE()”,那么两个 CE 的估计值都是正确的。湾。这是相同的查询,但估计对于 CE 120 是正确的,而不是对于 CE 70? GETDATE() 改变了行为吗?另外,请参阅问题中的其他信息 @carsten Cardinality Estimator 部分记录,所以对你的问题没什么好说的...... :(以上是关于为啥过滤统计信息被忽略的主要内容,如果未能解决你的问题,请参考以下文章