SQL Server统计信息更新时采样百分比对数据预估正确性的影响详解
为何要写统计信息
最近看到园子里有人写统计信息,楼主也来凑热闹。
话说经常做数据库的,尤为是做开发的或者优化的,统计信息造成的机能题目应当说是司空见惯。
当然解决办法也并非一成不变,“一招鲜吃遍天”的做法已经行不通了(题外话:整个时期不都是这模样吗)
当然,还是那句话,既然写了就不能太俗套,写点不同的,本文通过剖析一个相似现实案例来解读统计信息的更新的相干题目。
关于现实题目,不光要解决题目,更重要的是要从理论上深入剖析,才能更好地驾驭数据库。
何时更新统计信息
(1)查询施行迟缓,或者查询语句忽然施行迟缓。这种场景很可能是因为统计信息没有及时更新而遭遇了参数嗅探的题目。
(2)当大量数据更新(INSERT/DELETE/UPDATE)到升序或者降序的列时,这种状况下,统计信息直方图可能没有及时更新。
(3)倡议在除索引保护(当你重建、整理碎片或者重组索引时,数据散布不会转变)外的保护工作之后更新统计信息。
(4)数据库的数据更改频繁,倡议最低限度天天更新一次统计信息。数据仓库可以恰当降低更新统计信息的频率。
(5)当施行规划涌现统计信息缺失告诫时,需要手动创立统计信息
统计信息根基
首先说一个老掉牙的话题,统计信息的更新阈值:
1,表格从没有数据变成有大于等于1条数据。
2,关于数据量小于500行的表格,当统计信息的第一个字段数据累计变化量大于500今后。
3,关于数据量大于500行的表格,当统计信息的第一个字段数据累计变化量大于500 + (20%×表格数据总量)今后。
做个查询,触发统计信息更新,rowmodct归0(继续累积直到下一个触发的阈值,触发更新之后再次归0)
对于统计信息“逾期”的题目
下面开端正文,网络上许多对于统计信息的文章,提到统计信息,许多都是统计信息逾期的题目,然后跟新之后怎么怎么样
尤为在触发统计信息主动更新阈值的第三个区间:也就是说数据累计变化超过20%之后才能主动触发统计信息的更新
这一点关于大表来说平常影响是比较大的,比方1000W的表,变化超过20%也+500也就是200W+500行之后才触发统计信息更新,这个阈值区间的主动触发阈值,绝大多数状况是不能承受的,于是关于统计信息的诊断就变成了是否“逾期”
判断统计信息是否逾期,然后通过更新统计信息来促使施行规划更加正确地预估行数,这一点本无可厚非
但是,题目也就出在这里了:那么怎么更新统计信息?一成不变的做法是否可行,这才是题目的重点。
当然确定有人说,我就是按照默许方式更新的,更新完之后SQL也变得更加优化了什么的
通过update statistics TableName StatisticName更新某一个索引的统计信息,
或者update statistics TableName更新全表的统计信息
这种状况下往往是小表上可以这么做,当然关于大表或者小表没有一个规范值,一切要联合事实来注明题目
下面开端本文的主题:
抽象并简化出业务中的一个现实案例,创建这么一张表,相似于订单和订单明细表(主子表),
这里你可以想象成是一个订单表的子表,Id字段是独一的,有一个ParentID字段,是非独一的,
ParentID相似于主表的Id,测试数据按照一个主表Id对应50条子表明细的纪律插入数据
CREATE TABLE [dbo].[TestStaitisticsSample]( [Id] [int] IDENTITY(1,1) NOT NULL, [ParentId] [int] NULL, [OtherColumn] [varchar](50) NULL ) declare @i int=0 while(@i<100000000) begin insert into [TestStaitisticsSample](ParentId,OtherColumn)values(@i,NEWID()) /* 中间插入50条,也即一个主表Id对应50条子表明细 */ insert into [TestStaitisticsSample](ParentId,OtherColumn)values(@i,NEWID()) set @i=@i+1 end go create nonclustered index [idx_ParentId] ON [dbo].[TestStaitisticsSample] ( [ParentId] ) go
原来打算插入1亿条的,中间我让他施行我睡午觉去了,醒来之后发明SSMS挂掉了,挂掉了算了,数据也接近1亿了,能注明题目就够了
此刻数据散布的非常明白,就是一个ParentId有50条数据,这一点首先要澄清。
测试数据写入,以及所创建完成之后来更新idx_ParentId 索引上的统计信息,就按照默许的方式来更新,然后来调查统计信息
默许方式更新统计信息(未指定采样密度)
表里此刻是8000W多一点记载,默许更新统计信息时取样行数是462239行,那么这个统计信息靠谱吗?
上面说了,造数据的时候,我一个ParentId对应的是50行记载,这一点非常明白,他这里统计出来的多少?
1,关于取样的RANG_HI_Key值,比方51632,预估了862.212行
2,关于AVG_RANG_ROW,比方45189到51632之间的每个Id的数据对应的数据行,预估是6682.490行
以前造数据的时候每个Id都是50行,这里的预估靠谱吗,这个误差是没法承受的,
许多时候,关于大表,采纳默许(未指定采样密度)的状况下,默许的采样密度并不够以正确地描述数据散布状况
指定一个采样密度的方式更新统计信息(20%采样)
这一次用20%的采样密度,可以看到取样的行数是15898626行
1,关于取样的RANG_HI_Key值,比方216305,他给我预估了24.9295行
2,关于AVG_RANG_ROW,比方186302到216305之间的每个Id的行数,预估是197.4439行
调查比方上面默许的取样密度,这一次无论是RANG_HI_Key还是AVG_RANG_ROW得预估,都有不一个非常高的下降,开端趋于接近于真实的数据散布(每个Id有50行数据)
整体上看,但是这个误差还是比较大的,要是继续提高采样密度,看看有什么变化?
指定一个采样密度的方式更新统计信息(70%采样)
这一次用70%的采样密度,可以看到取样行数是55962290行
1,关于取样的RANG_HI_Key值,比方1978668,预估了71.15906行
2,关于AVG_RANG_ROW,比方1124024到1978668之间的每个Id,预估为61.89334行
可以说,关于绝大多数值得预估(AVG_RANG_ROW),都愈发接近于真实值
指定一个采样密度的方式更新统计信息(100%采样)
可以看到,取样行数等于总行数,也就是所谓的全部(100%)取样
看一下预估效果:
比方Id=3981622,预估是50行,3981622与4131988之间的Id的行数,预估为49.99874行,根本上等于真实数据散布
这个就不做过多解释了,根本上跟真实值是同样的,只是AVG_RANG_ROW有一点非常非常小的误差。
取样密度上下与统计信息正确性的关系
至于为何默许取样密度和较低取样密度状况下,误差很大的状况我简略解释一下,也非常容易了解,由于“子表”中存储主表ID的ParentId值允许反复,在存在反复值的状况下,要是采样密度不足,极有可能造成“以偏概全”的状况
比方对10W行数据取样1W行,原本10W行数剧中有2000个不反复的ParentId值,要是是10%的取样,在1W行取样数据中,由于密度不足大,只找到了20个不反复的ParentId值,那么就会以为每一行ParentId对应500行数据,这根现实的散布的每个ParentId有一个非常大的误差范畴
要是提高采样密度,那么这个误差就会越来越小。
更新统计信息的时候,高比例的取样是否可取(可行)
因而在调查统计信息是否逾期,决议更新统计信息的时候,一定要注意取样的密度,就是说表中有多少行数据,统计信息更新的时候取了多少采样行,密度有多高。
当然,确定有人质疑,那你说采样密度越高,也就是取样行数越高越正确,那么我就100%取样。
这样行不行?
还要分状况看,关于几百万或者十几万的小表来说,当然没有题目,这也是为何数据库越小,表数据越少越容易掩盖题目的缘由。
关于大表,上亿的,甚至是十几亿的,你按照100%采样试一试?
举个现实例子:
我这里对一个略微大一点的表做个全表统计信息的更新,测试环境,服务器没负载,存储是比普通的机械硬盘要强许多的SAN存储
采纳full scan,也就是100%采样的更新操纵,看一下,仅仅这同样表的update statistic操纵就破费了51分钟
试想一下,对一个数百GB甚至数TB的库来说,你敢这么搞一下。
扯一句,这个中秋节过的,折腾了大半天,话说做测试历程中电脑有开端有点卡,
做完测试之后停掉SQLServer服务,瞬间内存释放了7个G,可见这些个操纵还是比较耗内存的
总结:
本文通过关于某些场景下,在对较大的表的索引统计信息更新时,采样密度的剖析,阐述了不一样采样密度下,对统计信息预估的正确性的影响。
当然关于小表,一些都好说。
随着单表数据量的添加,统计信息的更新战略也要做响应的调整,
不但要看统计信息是否“逾期”,更重要的是注意统计信息更新时毕竟取样了全表的多少行数据做统计。
关于大表,采纳FULL SCAN或者100%采样往往是不可行的,这时候就需要做出权衡,做到既能正确地预估,又能够以合理的代价施行。
好了,以上就是这篇文章的全部内容了,但愿本文的内容对大家的学习或者工作拥有一定的参考学习价值,要是有疑难大家可以留言交换,感谢大家对我们的支撑