理解统计信息(4/6):自动更新统计信息的阀值——人为更新统计信息的重要性

理解统计信息(3/6):谁创建和管理统计信息?在性能调优中,统计信息的作用里我们讨论了统计信息的自动创建和自动更新。我们真的需要人为维护统计信息来保持性能最优?答案是肯定的,这取决与你的工作量。SQL Server只在达到阀限值时进行统计信息的自动更新。当大量的Insert/Update/Delete操作发生时,内建的自动更新统计信息不能持续保证性能的最优。

经过一系列的Insert/Update/Delete后,统计信息可能不会是最新。如果SQL Server查询优化器在表里需要指定列的统计信息,自上次统计信息创建或更新后经历了实质的更新活动,SQL Server会通过采样列值自动更新统计信息(通过自动更新统计信息)。统计信息的自动更新由查询优化器或编译好的计划执行来触发,它只涉及到查询里引用到的各个列。如果自动异步更新统计信息是停用的话,统计信息会在查询编译前更新,启用的话是在查询编译后更新。当统计信息是异步更新时,受益于触发更新的查询使用老的统计信息。对一些工作量来说,这可以提供更可预估的响应时间,尤其是那些大表上的短时间运行的查询。

当一个查询首次编译完成,如果优化器需要指定对象的统计信息,这个统计信息存在的话,若已过期则自动更新统计信息。如果一个查询被执行且它的计划在缓存里,计划依赖的统计信息会被检查是否过期,如果过期,计划会在缓冲中移除,在查询的重编译时,统计信息会被更新。如果计划依赖的任何统计信息被更新的话,计划都会从缓存中移除。

SQL Server 2008基于列修改的计数器(colmodctrs)来决定是否更新统计信息:

在下列情况下,统计信息对象被认为过期:

如果在常规表上定义的统计信息,被认为过期的话,那么:

  1. 表的大小从0行变成了大于0行(测试1)
  2. 当统计信息收集时,表的行数为500或更少,统计的主要列对象的计数器,自改变为大于500时(测试2)。
  3. 当统计信息收集时,表的行数大于500时,统计的主要列对象的计数器,受表里超过500 +20%的行数而改变(测试3)。

上述描述来自微软的MSDN,具体参见Statistics Used by the Query Optimizer in Microsoft SQL Server 2008

前2个条件还是相当好的,但第3个条件在处理大表时,有些时候阀值会很高,但对统计信息更新还是无效。例如有个表有100000条记录,只有在200500条件记录被修改后(update/insert),对于触发自动更新还是无效的阀值。

我们来看个例子。

1 USE StatisticsDB
2 GO
3
4 DROP TABLE SalesOrderDetail
5 SELECT * INTO SalesOrderDetail FROM AdventureWorks2008r2.sales.SalesOrderDetail
6 CREATE INDEX ix_ProductID ON SalesOrderDetail(ProductID)
7 SET STATISTICS IO ON
8 SELECT * FROM SalesOrderDetail WHERE ProductID=725

我们创建了SalesOrderDetail表的副本,并在上面创建非聚集索引,我们看下最后SELECT查询的执行计划,点击工具栏的显示包含实际的执行计划。

优化器选择了索引查找和书签查找操作作为优化的计划,完成这个操作需要377个逻辑读。

salesOrderDetail 表有121317条记录,上述第3个条件如果要使统计信息无效的话,121317的20% =24263+500=24763条记录需要被修改,我们用下列语句只更新5000条记录,再次看看查询的执行计划,点击工具栏的显示包含实际的执行计划。

1 SET ROWCOUNT 5000
2 UPDATE SalesOrderDetail SET ProductID=725 WHERE ProductID<>725
3 SET ROWCOUNT 0
4 SET STATISTICS IO ON
5 SELECT * FROM SalesOrderDetail WHERE ProductID=725

执行计划里估计行数是374,这是基于上次更新操作收集的统计信息。优化器基于统计信息,选择了索引查找和书签查找作为最优计划。SELECT操作进行5390逻辑读来完成这个操作。

下一步,我们用producid值为725来更新19762条记录。实际上我们更新24762条记录(包含上一步5000条更新的记录),比使统计信息无效的更新的记录(24763)少1条。

1 SET ROWCOUNT 19762
2 UPDATE SalesOrderDetail SET ProductID=725 WHERE ProductID<>725
3 SET ROWCOUNT 0
4 SET STATISTICS IO ON
5 SELECT * FROM SalesOrderDetail WHERE ProductID=725

执行计划里估计行数是374,这是基于上次更新操作收集的统计信息。优化器基于统计信息,选择了索引查找和书签查找作为最优计划。完成这个操作需要25206个逻辑读。

现在我们更新再多一条记录使统计信息无效。

1 SET ROWCOUNT 1
2 UPDATE SalesOrderDetail SET ProductID=725 WHERE ProductID<>725
3 SET ROWCOUNT 0
4 SET STATISTICS IO ON
5 SELECT * FROM SalesOrderDetail WHERE ProductID=725

(这里我跌了个跟头,在SQL SERVER 2008R2里首次执行,始终是下列结果:

回家吃饭还在思考这个问题,一想原因,应该是自动创建统计信息和自动更新统计信息被停用的原因(上篇文章理解统计信息(3/6):谁创建和管理统计信息?在性能调优中,统计信息的作用 代码执行后未还原为默认设置),在数据库属性里一看,果然是False状态,赶紧用下列语句启用,出现的问题立马消失!

1 ALTER DATABASE StatisticsDB SET AUTO_CREATE_STATISTICS ON
2 ALTER DATABASE StatisticsDB SET AUTO_UPDATE_STATISTICS ON

看来计算机是最诚实可靠的,即使计算机犯了错,也是因为人犯错造成的!

和我们预期的一样,SELECT语句触发了自动更新统计信息,计划中的估计行数和实际行数已经非常接近了。这可以帮助优化器选择更好的执行计划。优化器选择了表扫描而不是索引查找和书签查找。SELECT操作只进行了1495个逻辑读来选取25137条记录,比起25212个逻辑读才选择2516条记录。在第一步,我们只更新了5000条记录,如果统计信息在那个时候更新的话,优化器可能会选择表扫描作为最优计划而不是索引查找和书签查找。那样的话就可以只用1495个逻辑读代替5390个逻辑读来完成操作,这样就会好很多。

从这个例子我们可以清楚看到,对于自动更新统计信息的阀值对于获得最优性能还是不够好。对于大表来说会更糟。我们就需要人为去更新统计信息用来保证长须的最佳性能,当然更新的频率要看具体的工作量。

在进行大量DML操作后,统计信息都会过期,在查询计划访问统计信息前,统计信息都不会自动更新。更清楚的说,SQL Server会在下列情况自动更新统计信息:

  • 查询第一次编译,计划使用到的统计信息已经过期
  • 查询已有存在的查询计划,但计划中的统计信息已经过期。
时间: 2024-10-11 00:16:46

理解统计信息(4/6):自动更新统计信息的阀值——人为更新统计信息的重要性的相关文章

还原数据自动管理的一些参数和获得还原数据信息

一.oracle还原数据自动管理的一些参数: 1.oracle 9i之前的一些程序中开发的脚步上包含手动指定回滚段的语句.这样的语句在执行是虽然对最终结果没有影响但是会在控制台报错,对用户的感觉不好.故引入动态参数 UNDO_SUPPRESS_ERRORS那么在自动管理还原数据的模式下手动指定或设置还原段虽然对最终结果没有影响但是不会在控制台报错. alter session set  undo_suppress_errors=true; 2.UNDO_RETENTION该参数决定了为了保证读一

统计一下ie的一些问题(什么时候遇到什么时候更新)

1.document.createElement问题 问题描述:在用ASP.NET的时候,通常我们需要注册脚本,通常是以这种形式发送到客户端: <script type="text/javascript"> //<![CDATA[ layer.alert('请先登录!', -1, '提示',function () { location.href='/Login.aspx';});//]]> </script> 但是这段脚本,在ie8以及以上版本没什么

集合HashMap来统计单个字在字符串中出现的次数(用hashmap来统计)

/* * 统计单个字在字符串中出现的次数(用hashmap来统计) * * 分析 : * 1.先建立一个字符串 * 2.把字符串转换为数组 * 3.创建一个hashmap * 4.遍历数组,得到每个字符 * 5.拿得到的字符作为健到集合中去找值.得到返回值 * 是null:把字符作为键,1为值存入集合 * 不是null: 则把值加1重新写入集合 * 6.遍历输出 * */ import java.util.HashMap; import java.util.Map.Entry; import j

Git的纯命令操作,Install,Clone , Commit,Push,Pull,版本回退,撤销更新,分支的创建/切换/更新/提交/合并,代码冲突

Git的纯命令操作,Install,Clone , Commit,Push,Pull,版本回退,撤销更新,分支的创建/切换/更新/提交/合并,代码冲突 这篇是接着上篇分布式版本库--Windows下Git的环境部署以及在GitHub上开源自己的项目讲的,上篇主要是说用GUI来图形化界面操作,但是一般我们程序员也不会这么干,用命令又轻松又愉悦,所以,这里我就再开了一篇来专门说一下纯命令是怎么去操作的,但是要注意哦,其实廖雪峰老师的网站就是非常赞的学习资源哦! 廖雪峰老师:http://www.li

快照更新迟缓,这个和网站更新还有SEO搜索引擎友好度

<p> <br>怎么样重新恢复网站之前的排名<br>怎么样从头恢复上网站之前的排名 <br>第一:首页没有收录的措置体例,即是对首页的内容从事年夜量的更新,更新的内容都若是原创,内容能够不吸惹人,可是必定要是原创,内容也不在于多,关头是Baidu能抓取到,然后去做外链,让蜘蛛去爬行,一旦感受我们有更新,可能初度没有抓取,可是下次差不多了,再有体式格局就是找伴侣换一个单链的友链,当然这个网站必定要是正常的.<br>第二:网站彻底被k失踪,这个更麻烦

Win10一周年更新正式版首个累积更新补丁14393.51开始推送

9月28日消息,今天微软唐娜姐除了推送Win10一周年更新预览版14393.67外,还面向Win10一周年更新正式版用户推送最新累积更新补丁KB3176495,版本号是14393.51,本次更新仅适合正式版,因此Win10 Mobile还不能收到更新. 已经升级到Win10一周年更新正式版且没有参加Windows Insider项目测试版的炸金花,如果还没有收到更新,现在可以到设置——Windows更新中进行手动检查获取更新.

【C语言】用结构体数组指针完成:有三个学生信息,存放在结构体数组中,要求输出全部信息

//用结构体数组指针完成:有三个学生信息,存放在结构体数组中,要求输出全部信息 #include <stdio.h> struct Stu { int num; char name[20]; char sex; int age; }; int main() { struct Stu student[3]={{317,"han",'m',20},{318,"hun",'w',22},{311,"dan",'w',18}}; struct

好久没更新了,哪里不对!更新二叉树的非递归遍历

#include <iostream> #include <stack> using namespace std; typedef struct Node { Node* lchild; Node* rchild; int data; }BNode,BTree; void visit(Node*); void inorder(BTree *root) { BNode * p = root; stack<Node*> s; if(p||!s.empty()) { s.pu

乌班图的世界——更新目录查看与真正的更新

查看更新 apt update 查看更新目录apt list --upgradable执行更新 原文地址:http://blog.51cto.com/shujuliu/2170517