不正确的 SQL Server 统计信息
Posted
技术标签:
【中文标题】不正确的 SQL Server 统计信息【英文标题】:Improper SQL Server statistics 【发布时间】:2021-12-24 19:24:41 【问题描述】:我有大表和具有 3 个 int 字段的聚集索引的简单情况。当我使用前 2 个过滤时,估计的行数不正确,因为统计数据显示错误的数字。这是在 SQL Server 2019 CU12 上测试的。所有 SQL Server 版本都存在同样的问题。我测试的最低版本是带有所有服务包的 SQL 2008。
这是我的 SQL 代码(示例)
create table dbo.glp_test (NagId bigint not null, Lp bigint not null,Id bigint not null, opis varchar(200), CONSTRAINT BK_glp_test PRIMARY KEY CLUSTERED(NagId, Lp, id))
GO
create function dbo.genNum(@start int, @end int)
returns @t table (num int not null identity(1,1))
begin
while @start<=@end
begin
insert into @t default values
set @start = @start+1;
end
return;
end
GO
insert into dbo.glp_test (NagId, lp, Id, opis)
select s.Num, c.Num, c.Num*c2.Num, convert(varchar(100), c.Num*c2.Num)
from dbo.genNum(1,10000) s
cross apply dbo.genNum(1,30) c
cross apply dbo.genNum(1,30) c2
GO
update statistics glp_test with fullscan
GO
dbcc show_statistics('glp_test','BK_glp_test')
GO
-- select [rows]*[All density]
select 9000000*3.333333E-06 -- 29,999997 - correct
GO
update statistics glp_test
GO
dbcc show_statistics('glp_test','BK_glp_test')
GO
-- select [rows]*[All density]
select 9000000*8.609557E-05 -- 774,86013 - dramatically incorrect
GO
现在,如果我使用字段 1 和字段 2 的确切值查询表 glp_test,则估计的行数是错误的。估计应该接近 30。使用全扫描更新统计信息可以解决问题,但这不是解决方案。如何解决这个问题?
declare @Nagid bigint, @Lp bigint
select * from dbo.glp_test where NagID = @NagId and Lp = @Lp
【问题讨论】:
仅供参考,我真的建议不要使用这些功能。众所周知,多行表值函数的性能很差,而带有WHILE
的函数的性能会很糟糕。
函数 genNum 只是技术问题,与统计问题没有任何共同之处
CU13 适用于 SQL Server 2019,也许您遇到的任何错误都可能已经修复。问题可能是统计数据过时,也许更新统计数据可以解决问题?
简单更新统计信息并不能解决问题。只有全扫描可以。由于问题甚至出现在 SQL 2008 中,我认为他们无法在 CU13 中解决它。
【参考方案1】:
我认为这与在没有 WITH FULLSCAN 的情况下运行更新统计信息时发生的默认采样有关。请参阅此link,其中 Joe Sack 在他所做的测试中显示了抽样百分比。请注意,默认采样率大幅下降。
【讨论】:
FULLSCAN 需要更多的时间和资源。从我的角度来看,这听起来像是一个错误,因为我希望前两个字段 (0-30) 的值介于 0 和最大数量之间。任何超过此值的值对于它所采用的任何样本都是无效的。以上是关于不正确的 SQL Server 统计信息的主要内容,如果未能解决你的问题,请参考以下文章