为什么要写统计信息

  最近看到园子里有人写统计信息,楼主也来凑热闹。
  话说经常做数据库的,尤其是做开发的或者优化的,统计信息造成的性能问题应该说是司空见惯。
  当然解决办法也并非一成不变,“一招鲜吃遍天”的做法已经行不通了(题外话:整个时代不都是这样子吗)
  当然,还是那句话,既然写了就不能太俗套,写点不一样的,本文通过分析一个类似实际案例来解读统计信息的更新的相关问题。
  对于实际问题,不但要解决问题,更重要的是要从理论上深入分析,才能更好地驾驭数据库。

统计信息基础

首先说一个老掉牙的话题,统计信息的更新阈值:
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%采样往往是不可行的,这时候就需要做出权衡,做到既能准确地预估,又能够以合理的代价执行。

SQL Server 统计信息更新时采样百分比对数据预估准确性的影响的更多相关文章

  1. 全废话SQL Server统计信息(2)——统计信息基础

    接上文:http://blog.csdn.net/dba_huangzj/article/details/52835958 我想在大地上画满窗子,让所有习惯黑暗的眼睛都习惯光明--顾城<我是一个 ...

  2. 全废话SQL Server统计信息(1)——统计信息简介

    当心空无一物,它便无边无涯.树在.山在.大地在.岁月在.我在.你还要怎样更好的世界?--张晓风<我在> 为什么要写这个内容? 随着工作经历的积累,越来越感觉到,大量的关系型数据库的性能问题 ...

  3. SQL Server统计信息:问题和解决方式

    在网上看到一篇介绍使用统计信息出现的问题已经解决方式,感觉写的很全面. 在自己看的过程中顺便做了翻译. 因为本人英文水平有限,可能中间有一些错误. 假设有哪里有问题欢迎大家批评指正.建议英文好的直接看 ...

  4. SQL Server 统计信息(Statistics)-概念,原理,应用,维护

    前言:统计信息作为sql server优化器生成执行计划的重要参考,需要数据库开发人员,数据库管理员对其有一定的理解,从而合理高效的应用,管理. 第一部分 概念 统计信息(statistics):描述 ...

  5. SQL Server 统计信息的创建与更新

    前期准备: 普通表.临时表:它两会有统计信息. 表变量:           不会有统计信息. ---------------------------------------------------- ...

  6. SQL SERVER 统计信息概述(Statistics)

    前言 查询优化器使用统计信息来创建可提高查询性能的查询计划,对于大多数查询,查询优化器已经为高质量查询计划生成必要的统计信息,但是在少数情况下,您需要创建附加的统计信息或者修改查询设计以得到最佳结果. ...

  7. SQL Server 统计信息

    SELECT * FROM SYS.stats _WA_Sys_00000009_00000062:统计对象的名称.不同的机器名称不同,自动创建的统计信息都以_WA_Sys开头,00000009表示的 ...

  8. SQL Server统计信息偏差影响表联结方式案例浅析

      我们知道数据库中的统计信息的准确性是非常重要的.它会影响执行计划.一直想写一篇关于统计信息影响执行计划的相关博客,但是都卡在如何构造一个合适的例子上,所以一直拖着没有写.巧合,最近在生产环境中遇到 ...

  9. SQL Server 统计信息对查询的影响

    优化器根据开消确定选择哪个执行计划,开消又与行数统计信息有关,默认情况下统计信息是在优化的过程中自动生成的. 一旦列被标记为需要统计信息,查询优化器就会查找该列以有的统计信息,如果以有一个统计信息,下 ...

随机推荐

  1. redux-amrc:用更少的代码发起异步 action

    很多人说 Redux 代码多,开发效率低.其实 Redux 是可以灵活使用以及拓展的,经过充分定制的 Redux 其实写不了几行代码.今天先介绍一个很好用的 Redux 拓展-- redux-amrc ...

  2. 阿里签名中URLEncode于C#URLEncod不同之处

    问题 如上图所示,阿里云的PercentEncode 转换! 为 %21 PercentEncode 源码为: package com.aliyuncs.auth; import java.io.Un ...

  3. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  4. javascript匹配各种括号书写是否正确

    今天在codewars上做了一道题,如下 看上去就是验证三种括号各种嵌套是否正确书写,本来一头雾水,一种括号很容易判断, 但是三种怎么判断! 本人只是个前端菜鸟,,不会什么高深的正则之类的. 于是,在 ...

  5. Hawk 7. 常见问题

    本页面您可以通过关键字搜索来获取信息. 理性使用爬虫 爬虫是一种灰色的应用,虽然作为Hawk的设计者,但我依然不得不这么说. 各大网站都在收集和整理数据上花费了大量的精力,因此抓取的数据应当仅仅作为科 ...

  6. 开发者接入 基本配置 服务器配置 out.aspx

    页面代码: 前段为默认的,什么都不用写,后台如下: 即可 来自为知笔记(Wiz)

  7. iOS逆向工程之Hopper中的ARM指令

    虽然前段时间ARM被日本软银收购了,但是科技是无国界的,所以呢ARM相关知识该学的学.现在看ARM指令集还是倍感亲切的,毕竟大学里开了ARM这门课,并且做了不少的实验,当时自我感觉ARM这门课学的还是 ...

  8. 高德地图api实现地址和经纬度的转换(python)

    利用高德地图web服务api实现地理/逆地址编码 api使用具体方法请查看官方文档 文档网址:http://lbs.amap.com/api/webservice/guide/api/georegeo ...

  9. 【HTML】Html页面跳转的5种方式

    目录结构: // contents structure [-] html实现 javascript方式实现 结合了倒数的javascript实现(IE) 解决Firefox不支持innerText的问 ...

  10. JavaScript学习笔记(二)——闭包、IIFE、apply、函数与对象

    一.闭包(Closure) 1.1.闭包相关的问题 请在页面中放10个div,每个div中放入字母a-j,当点击每一个div时显示索引号,如第1个div显示0,第10个显示9:方法:找到所有的div, ...