我在理解Cardinality Estimator
如何使用过滤统计信息方面遇到了一些问题。
当我在CE 120
上运行查询时,它会产生预期的估算值,但是当我切换到CE 70
时,它似乎会忽略过滤后的统计信息。
此外,如果我不使用CE 120
子句中的实际统计信息列,WHERE
似乎会忽略已过滤的统计信息。
在脚本下面创建并填充测试表以及创建过滤后的统计信息。
/*
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行实际
值得注意的是,它没有为个人自动创建统计数据 列
当我们使用CE 70
SELECT *
FROM Test_FS
WHERE a = 'A1'
AND b = 'B1'
AND c >= GETDATE()
OPTION(RECOMPILE, QUERYTRACEON 9481)
它会忽略过滤的统计数据并估计2.88行。
请注意,我们现在为各个列自动创建了统计信息
statistics_name
_WA_Sys_00000002_3587F3E0
_WA_Sys_00000003_3587F3E0
_WA_Sys_00000004_3587F3E0
Test_FS_Filter_Stat
为什么CE 70
会忽略已过滤的统计信息?
我感觉GETDATE()
造成了它,但我不明白为什么以及可以做些什么。
现在在过滤后的统计CE 120
列上运行target
无条件的查询 - 仅限过滤列上的条件。
SELECT *
FROM Test_FS
WHERE a = 'A1'
AND b = 'B1'
OPTION(RECOMPILE)
这次它估计3.57771行,实际上返回2。
为什么不使用过滤后的统计信息 - 总行数没有?
我查看了为上述查询加载的统计信息,结果如下:
问题1:
当谓词是' > = GETDATE()'时,CE 70会忽略过滤的统计数据。但是当' = GETDATE()'时使用它已指定。如果指定了日期常量,则CE 70在两种情况下都使用过滤统计。
CE 120在上述所有情况下都使用过滤统计数据。
问题2:
当没有在' c'上指定谓词时,CE都完全忽略了Filtered Stats。我觉得很奇怪,因为这应该给他们最好的估计。
答案 0 :(得分:0)
回答第一个问题: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的执行计划: