Sql Server优化---统计信息维护策略
本文出处:http://www.cnblogs.com/wy123/p/5748933.html
首先解释一个概念,统计信息是什么:
简单说就是对某些字段数据分布的一种描述,让SQL Server大概知道预期的数据大小,从而指导生成合理执行计划的一种数据库对象
默认情况下统计信息的更新策略:
1,表数据从0行变为1行
2,少于500行的表增加500行或者更多
3,当表中行多于500行时,数据的变化量大于500+20%*表中数据行数
非默认情况下,促使已有统计信息更新的因素(包括但不限于下面三种,别的我也没想起来):
1,rebulid\Reorg index
2,主动update statistics
3,数据库级别的sp_updatestats
开始问题:
对于大表的更新策略是:数据的变化量大于500+20%*表中数据行数
比如对于1000W数据量的表,数据变化要超过500+1000W*20%=2,000,500之后才能触发统计信息的更新,
这一点大多数情况下是无法接受的,为什么?因为该规则下触发统计信息更新的阈值太大,会导致某些统计信息长期无法更新,
由于统计信息导致的执行计划不合理的情况已经在实际业务中屡见不鲜,对于统计信息的更新已经显得非常必要
同时,仅仅靠sqlserver自己更新统计信息,也不一定可靠,因为统计信息中还要一个取样行数的问题,这个也非常重要
因为SQL Server默认的取样行数是有上限的(默认取样,未指定取样百分比或者SQL Server自动更新统计信息时候的取样百分比),
这个上限值在100W行左右(当然也不肯定,只是观察),对于超过千万行的表,这个取样比例还是非常低的
比如下图超过3亿行的表,更新统计信息时候未指定取样百分比,默认取样才去了84万行)
据楼主的观察看,对于小表,不超过500W行的表,默认的取样比例是没有问题的,对于较大的表,比如超过500W行的表(当然这个500W行也是一个参考值,不是绝对值)
因此说默认取样比例是根本无法准确描述数据分布的。
由此看来,人工介入统计信息的更新是非常有必要的。那么如何更新索引的统计信息,有没有一种固定的方式?答案是否定的。
首先来看能够触发统计信息更新的方式
1,Rebulid\Reorg index
当然Rebulid\Reorg索引只是附带更新了索引的统计信息,主要是为了整理了索引碎片,
对于大表,代价相当大,数据库的维护策略,没有一概而论的方法,
对于较小的数据库或者是较小的表,比如几十万几百万的表,每天一个rebuild index都可以,
但是这种经验移植到大一点的数据库上恐怕就不好使了(正如名人的成功经验不可复印一样,每个人生活的环境不一样,不能一概而论)。
这种Rebulid\Reorg index对资源的消耗以及时间代价上都会相当大,甚至有些情况下是不会给你机会这么做的。
比如下面rebuild一个复合索引的耗时情况,仅仅是一个表上的一个索引,就花费了5分钟的时间
一个业务复杂的表上有类似这么三五个索引也是正常的,
照这么算下去,如果全库或者是整个实例下的十几个库,每个库数百张表全部这么做,要多长时间,代价可想而知
说不定整都没整完,维护窗口期的时间就到了,除非数据库不大(究竟大小的临界值为多少?个人觉得可以粗略地认为100GB吧),否则是不可以这么做的。
因此可以认为:通过重建或者重组索引来更新索引统计信息,代价太大了,基本上是不现实的。
2,update statistics
正是我想重点说的,因为我这里不具体说语法了,具体语法就不做详细说明了,
简单来说,大概有如下几种选择:
一种默认方式,另外还可以是全表扫描的方式更新,还有就是是指定一个取样百分比,如下:
--默认方式更新表上的所有统计信息
update statistics TableName
--对指定的统计信息,采用全表扫描的方式取样
update statistics TableName(index_or_statistics__name) with FullScan
--对指定的统计信息,采用指定取样百分比的方式取样
update statistics TableName(index_or_statistics__name1,index_or_statistics__name2) with sample 70 percent
相对于重建或者重组索引,update statistics 也是通过扫描数据页(索引页)的方式来获取数据分布,但是不会移动数据(索引)页,
这是Update Statistics代价相对于Rebuild索引小的地方(即便是Update Statistics的时候100%取样)
关键在于第三种方式:人为指定取样百分比,如果取样百分比为100,那跟FullScan一样
如果不用100,比如80,60,50,30,又如何选择?取样百分比越高,得到的统计信息越准确,但是代价越大,取样越小效率越高,但是误差的可能性会变大,怎么办,这就需要找一个平衡点。
那么究竟要取样多少,既能在更新统计信息的效率上可以接受,又能够使得统计信息达到相对准确地描述数据分布的目的,
这是还是一个需要慎重选择的问题,为什么?参考:http://www.cnblogs.com/wy123/p/5875237.html
如果统计信息取样百分比过低,会影响到统计信息的准确性,
如果过于暴力,比如fullscan的方式扫描,
参考下图,一个表就Update了50分钟(当然这是一个大表,上面有多个索引统计信息以及非索引统计信息)。如果有数十张类似的表,效率可想而知
总之就是,没有一个固定的方式,数据库不大,怎么做问题都不大,数据库一大,加上维护的窗口期时间有限,要在统计信息的质量和维护效率上综合考虑
3,数据库级别的sp_updatestats
用法:
exec sp_updatestats
或者
exec sp_updatestats @resample = 'resample'
指定 sp_updatestats 使用 UPDATE STATISTICS 语句的 RESAMPLE 选项。
对于基于默认抽样的查询计划并非最佳的特殊情况,SAMPLE 非常有用。
在大多数情况下,不必指定 SAMPLE,
这是因为在默认情况下,查询优化器根据需要采用抽样,并以统计方式确定大量样本的大小,以便创建高质量的查询计划。
如果未指定 'resample',则 sp_updatestats 将使用默认的抽样来更新统计信息。
默认值为 NO。
直接执行exec sp_updatestats更新统计信息,取样密度是默认的,
究竟这默认值是多少,MSDN上说默认情况下是“查询优化器根据需要采用抽样”,我想着采样算法应该没那么简单粗暴
目前也不知道具体是怎么一个算法或者采样方式,如果有知道园友的话请不惜赐教,谢谢
4,TraceFlag 2371
开启TraceFlag 2371之后,统计信息的变化是根据表做动态变化的,
打破了触发大表统计信息更新的当表中行多于500行时,数据的变化量大于500+20%*表中数据行数 阈值
参考:https://blogs.msdn.microsoft.com/saponsqlserver/2011/09/07/changes-to-automatic-update-statistics-in-sql-server-traceflag-2371/
在下图中,你可以看到新公式的工作方式,对于小表,阈值仍旧是在20%左右,
只有超过25000行之后,此动态规则才会被触发生效
随着表中数据行数的增加,(触发统计信息变更)的百分比会变的越来越低,
比如,对于100,00行的表,触发统计信息更新的阈值已经降低为10%,
对于1,000,000行的表,触发统计信息更新的阈值已经降低为3.2%。
对于10,000,000或者是50,000,000行的表,触发统计信息更新的阈值为少于1%或者0.5%,
而对于他100,000,000行的表,仅仅要求变化在0.31%左右,就可以出发统计信息的更新。
但是个人认为,这种方式也不一定靠谱,虽然开启TraceFlag 2371之后触发更新索引统计信息的阈值降低了,但是取样百分比还是一个问题,
之前我自己就有一个误区,看统计信息的时候只关注统计信息的更新时间(跟自己之前遇到的数据库或者表太小有关)
对于统计信息,及时更新了(更新时间比较新)不等于这个统计信息是准确的,一定要看取样的行数所占总行数的百分比
如何有效维护索引统计信息?
上面说了,要使获取相对准确的统计信息,就要在更新统计信息时候的取样百分比,
对于小表,即便按照其默认的变化阈值触发统计信息更新,或者是按照100%取样更新统计信息,都是没有问题,
对于大表,一定要考虑在其达到默认触发统计信息更新的阈值之前人为更新这个统计信息,但是大表的100%取样统计是不太现实的(性能考虑)
取样百分比越高,得到的统计信息越准确,但是代价越大,这就需要找一个平衡点,那么如果更新大表上的统计信息呢?
如果是认为干预统计信息的生成,就要考虑两个因素:一是数据变化了多少之后更新?二是更新的时候,以什么样的取样来更新?
我们知道,一个表的数据变化信息(增删改)记录在sys.sysindexes这个系统表的rowmodctr字段中,
该表的统计信息更新之后,该字段清零,然后再次累积记录表上的数据变化。
这个信息非常好使,为人工更新统计信息提供了重要的依据,
比如,对于1000W行的表,可以指定变化超过20W行(根据业务情况自定义)之后,手动更新统计信息,
对于5000W行的表,可以指定变化超过60W行(根据业务情况自定义)之后,手动更新统计信息,
同时根据不同的表,在相对较小的表上,指定相对较高的取样百分比,在相对较大的表上,指定相对较低的取样百分比
比如对于1000W行的表,更新统计信息的时候取样百分比定位60%,对于5000W行的表,更新统计信息的时候取样百分比定位30%
这样,可以自行决定数据变化了多少之后更新统计信息,以及动态地决定不同表的不同取样百分比,达到一个合理的目的。
当然,最后强调一下,我说的每一个数据都是相对的,而不是绝对的,都是仅做参考,
具体还要你自己结合自己的服务器软硬件以环境及维护窗口时间去尝试,一切没有死的标准。
总结:统计信息的准确性对执行计划的生成有着至关重要的影响,本文粗略分析了统计信息的跟新规律以及要更新统计信息时候要注意的问题,
在人为干预统计信息更新的时候,需要根据具体的情况(表数据流量,服务器软硬件环境,维护窗口期等)在效率与准确性之间作出合理的选择。
Sql Server优化---统计信息维护策略的更多相关文章
- SQL Server 中统计信息直方图中对于没有覆盖到谓词预估以及预估策略的变化(SQL2012-->SQL2014-->SQL2016)
本位出处:http://www.cnblogs.com/wy123/p/6770258.html 统计信息写过几篇了相关的文章了,感觉还是不过瘾,关于统计信息的问题,最近又踩坑了,该问题虽然不算很常见 ...
- SQL SERVER的统计信息
1 什么是统计信息 统计信息 描述了 表格或者索引视图中的某些列的值 的分布情况,属于数据库对象.根据统计信息,查询优化器就能评估查询过程中需要读取的行数及结果集情况,同时也能创建高质量的查询 ...
- SQL Server 查找统计信息的采样时间与采样比例
有时候我们会遇到,由于统计信息不准确导致优化器生成了一个错误的执行计划(或者这样表达:一个较差的执行计划),从而引起了系统性能问题.那么如果我们怀疑这个错误的执行计划是由于统计信息不准确引起的.那么我 ...
- SQL Server 更新统计信息出现严重错误,应放弃任何可能产生的结果
一台SQL Server 2008 R2版本(具体版本如下所示)的数据库,最近几天更新统计信息的作业出错,错误如下所示: Microsoft SQL Server 2008 R2 (SP2) - ...
- SQL Server 等待统计信息基线收集
背景 我们随时监控每个服务器不同时间段的wait statistics ,可以根据监控信息大概判断什么时候开始出现异常,相当于一个wait statistics基线收集,还可以具体分析占比高的等待类型 ...
- c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程
c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...
- 深入SQL Server优化【推荐】
深入sql server优化,MSSQL优化,T-SQL优化,查询优化 十步优化SQL Server 中的数据访问故事开篇:你和你的团队经过不懈努力,终于使网站成功上线,刚开始时,注册用户较少,网站性 ...
- SQL Server优化器特性-隐式谓词
我们都知道,一条SQL语句提交给优化器会产生相应的执行计划然后执行输出结果,但他的执行计划是如何产生的呢?这可能是关系型数据库最复杂的部分了.这里我为大家介绍一个有关SQL Server优化器的特性- ...
- SQL Server优化的方法
SQL Server优化的方法<一> 查询速度慢的原因很多,常见如下几种: 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了 ...
随机推荐
- KB奇遇记(1):开篇
我已经确定了2017年1月24日将是在旗滨工作的最后一天. 回顾从2015年8月3日入职那天开始到现在,一年半多的时间里的种种奇葩经历,深深被这家公司的制度.企业文化.官僚主义.粗糙的信息化建设以及利 ...
- HDU1175(dfs)
连连看 Time Limit:10000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Description ...
- 从新手到高手c++全方位学习 pdf + 视频教程 共18章
淘宝已经和谐了这个网站,原网址:https://item.taobao.com/item.htm?spm=a1z09.8149145.0.0.mb00D0&id=17350311256& ...
- JS消化理解
JS执行的时候是必须在网页里面执行,和样式表差不多,也是内嵌的样式表,嵌在网页里面或外部的! 一 嵌在网页里面怎么嵌? 如果你想在网页里面嵌脚本,你需要在网页里面打出一块区域,这块区域来写脚本,在写样 ...
- 关于a.b和a[b]的区别
在写代码的过程中,我们经常可以看到a.b或啊a[b],但是他们有什么区别呢: 简单说一下吧,有自己的还用群友的大力支持! 在js的对象中 var arr = {a:"b",b:&q ...
- iOS网络层设计感想
App的开发无外乎从网络端获取数据显示在屏幕上,数据做些缓存或者持久化,所以网络层极为重要.原来只是把AFNetwork二次封装了一下,使得调用变得很简单,并没有深层次的考虑一些问题. 前言 参考: ...
- <C++Primer>第四版 阅读笔记 第四部分 “面向对象编程与泛型编程”
继承和动态绑定与数据抽象一起成为面向对象编程的基础. 模板使我们能够编写独立于具体类型的泛型类和泛型函数. 第15章 面向对象编程 面向对象编程基于三个基本概念:数据抽象.继承和动态绑定.在C++中, ...
- canvas绘图不清晰的解决方案
现象描述 同样大小的图片(60x60px)用canvas和DOM绘制,结果发现canvas的画面质量要差很多.结果如下图所示. 上图中,左侧红框中的金币采用DOM绘制,右侧和下方的金币和文字等使用ca ...
- DOM树的增查改删总结
DOM树的增查改删总结 摘要:对HTML DOM的操作是前端JavaScript编程时必备的技能,本文是我自己对DOM树操作的总结,主要是方法的罗列,原理性的讲述较少,适合大家用于理清思路或是温习 一 ...
- 关于c# 基础运算符的应用
运算符 分为5种 1 算数预算符 +,-,*,/,分别为加减乘除 ++为加1,--为减1, 前++ 后++ 的区别 int a = 10, b = a++; Console ...