索引查找估计的行数

时间:2016-08-10 14:04:28

标签: sql-server cardinality

问题是关于MS SQL Server 2008 +。

有桌子(比方说,5-10M行)

CREATE NONCLUSTERED INDEX [IX_Persons_LastName_FirstName] 
ON [Test].[Persons] ([LastName] ASC, [FirstName] ASC)

使用索引

SELECT [FirstName],[LastName],[BirthDate] 
FROM [Test].[Persons] WHERE [LastName] = 'Decker'

执行简单查询,如

    "features": [
            {
                    "geometry": {
                            "coordinates": [
                                    16.91828856,
                                    52.3838415
                            ],
                            "type": "Point"
                    },
                    "id": "ROLN04",
                    "type": "Feature",
                    "properties": {
                            "zone": "A",
                            "route_type": "3",
                            "headsigns": "238",
                            "stop_name": "Rolna"
                    }
            },
            {
                    "geometry": {
                            "coordinates": [
                                    16.88799654,
                                    52.40252503
                            ],
                            "type": "Point"
                    },
                    "id": "RJNJ01",
                    "type": "Feature",
                    "properties": {
                            "zone": "A",
                            "route_type": "3",
                            "headsigns": "251",
                            "stop_name": "Rondo Jana Nowaka-JezioraĹskiego"
                    }
            },

我看到,使用 Index Seek 运算符,当键不在统计直方图精确值中时,估计的行与实际行的差异很大。
对于某些特定键,它可以是大约15个估计行vs 10k实际行。 在这种情况下似乎“Estimated rows”值直接取自AVG_RANGE_ROWS以获得相应的间隔(即下一个直方图值)。

这是预期的行为吗?我的意思是,SQL Server“知道”该值是不确切的并在计算查询成本中使用这一事实,或者它是一个潜在的错误查询计划问题?

尝试使用SQL2008R2,2012,2014(全部使用OLD基数估算器)据我所知,新CE仅在处理查询中的多个表时才会更改。尝试很有意思,但我还没有。

1 个答案:

答案 0 :(得分:0)

我在这个问题上做了一些工作并明确表达了。

简短回答:好吧,对我感到羞耻。这正是统计工作的方式。在我的情况下,额外的过滤统计数据将赢感谢您的评论,他们开始检查非常有用。

答案很长: “问题”在于数据密钥分配。我在直方图中填充了所有200个步骤,它无法收集有关确切非常常见值的更多信息。超过500k的相对罕见的不同值,它给我们带来了明显的效果(对我而言)。

我制作了一个简单的示例脚本,演示了类似的行为:

CREATE TABLE [TestStatistics] (
[Id] [INT] IDENTITY (1,1) PRIMARY KEY,
[Val] [INT] NOT NULL
)
GO
--Insert 200k rows with ~60k distinct values
insert into TestStatistics (Val) VALUES (CHECKSUM (newid())%30000)
go 200000
--Insert 100k rows with ~600 distinct values, that are multiples of 100
insert into TestStatistics (Val) VALUES (CHECKSUM (newid())%300*100)
GO 100000

create nonclustered index IX_TestStatistics_Val on TestStatistics(Val ASC)
GO

所以,我已经插入了300k总行,其中有大约60k个不同的值,这意味着表中的密度约为0.2。而且我有“特殊”的100k行,它们填充了~600个不同的值 - 100的倍数。也就是说,这些行中的任何行都会遇到~166次。 现在统计数据看起来像这样:

Statistics

现在,如果我采用100的倍数,直方图中没有(例如,7500),我将估计4.5-5.5行和近166个实际行。估计值实际上只是直方图中的下一个AVG_RANGE_ROWS值(对于7500 - 在Val = 7800)。

现在,如果我收集一些额外的统计数据,比如

CREATE STATISTICS ST_TestStatistics_0_10000 
ON TestStatistics(Val) WHERE Val>=0 AND Val<10000

我会得到另一个查询计划:

Query Plans