为什么要写统计信息
最近看到园子里有人写统计信息,楼主也来凑热闹。
话说经常做数据库的,尤其是做开发的或者优化的,统计信息造成的性能问题应该说是司空见惯。
当然解决办法也并非一成不变,“一招鲜吃遍天”的做法已经行不通了(题外话:整个时代不都是这样子吗)
当然,还是那句话,既然写了就不能太俗套,写点不一样的,本文通过分析一个类似实际案例来解读统计信息的更新的相关问题。
对于实际问题,不但要解决问题,更重要的是要从理论上深入分析,才能更好地驾驭数据库。
何时更新统计信息
(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
creatf^x~j~yNiNiki8KK^K^j~yGWFFR7FF7F>i8[KKcSXn)УУ^h;>KKKKi[yyI{>i[D.yN[>iKiZ.i K8#У7GFWBv6V"#8"7&3GG3F&'22V"c&cFFF&6#sVVFC#fcsr#У^KKx.[nZJ~XZJkXzKK^Ii[Zxix+XУZXYW'fW.iXΙ{NXh^ZxiKc~K~KKi8j ~Xh^ZyCУ"7&3GG3F&'22V"c##6SS#VFF#v&V6#&6S3cFbr#8УG66fc#G&h{>7G&7h~ KKYiZZJ~yNyN{J.[{hi{n~j~ZyNXniKΘx~j~ZK{hyNXxnz~yN[Y8#У>xKnZ[K;[У^i[hxhNikzyZ^Ky[NyN>i[NУXhy{hn( ( iNxhyNiKiNiki{nznz~KnXZyNZI[ [hX{#УK~~yJeT44nS^x~j~[Ni{nX [hXX{iXiz.;xnz(NK;IynyNK>K~h~#Уn^K[i~ih~zyNXZ:Xh^Zniih~yNXh^ZZNZKhn^[z^KX[~iKZNXZKK~XZh.iyiz~ZyYKNkX.
.ZJ~ZXyNiJ |