【发布时间】: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 都完全忽略了过滤的统计信息,我觉得这很奇怪,因为这肯定会给他们最好的估计。
【问题讨论】:
标签: sql-server sql-server-2012 statistics sql-server-2014 cardinality