一、索引在查询优化中的角色

  SQL Server的查询优化器是基于开销的优化器、它通过确认选择性、数据的唯一性以及过滤数据(通过WHERE或JOIN子句)所使用的列来决定最佳的数据访问机制。统计与索引一同存在,但是它们也作为断言的一部分存在于没有索引的列上。

  作为谓词引用的列中数据分布的最新信息帮助优化器确定所使用的查询策略。在SQL Server中,这个信息以统计的形式维护,这对于基于开销的优化器创建一个有效的查询执行计划是很重要的。通过统计,优化器能做出返回结果集或中间结果集所花费时间的精确估计,从而确定最高效的操作。只要确定数据库已经进行了默认的统计设置,优化器就能尽其所能地动态确定有效的处理策略。而且,作为性能问题诊断时的安全性度量,应该确定自动统计维护历程正在按照预想工作。如果有必要,甚至手工控制统计的创建或维护。

二、索引列上的统计

  索引的有效性完全取决于索引列上的统计。如果没有统计,SQL Server的基于开销的查询优化器将不能选择到使用索引最有效的方式。

  SQL Server默认会自动创建索引键的统计,不管它是何时创建的。

  我们知道,随着数据的变化,保持查询低开销的数据检索机制也会变化。例如,如果一个表对于某个列的值的选择性相当高为0.99,那么通过该列上的非聚集索引来检索匹配行是有意义的。但是如果表中数据变化,添加了大量该列有相同值的行选择性下降,那么使用这个非聚集索引就不再有意义。

  SQL Server可以使一个索引上的统计随着索引列内容变化而更新。默认情况下,这个特性被开启,而且可以通过属性=》选项=》数据库的自动更新统计设置来开启或关闭。

  

  更新统计消耗额外的CPU周期。为了优化和更新进行,SQL Server使用如下高效的算法来确定合适的更新统计时机:

  1. 当没有任何行的表得到一个行时;
  2. 当少于500行的表增加500行或更多行时;
  3. 当多于500行的表增加500+20%的行数时;

  这种内建的智能使每个进程的CPU利用率保持很低。也可以异步地更新统计。这意味着当查询正常地导致统计更新时,查询使用旧的统计继续,统计被离线更新。这可以加速一些查询的响应时间,比如在数据库很大或超时间隔很短时。

  可以使用ALTER DATABASE命令手工禁用(或启用)自动更新统计和异步更新统计特性,默认情况下,自动更新统计特性被启用(强烈建议保持启用)。自动异步更新统计特性默认下被禁用,只有确定它能在数据库上对超时有帮助时才开启这一特性。

  1、更新统计的好处以及过时统计的缺点示例

  执行自动更新的好处通常要超过其在系统资源上的开销,自动更新统计能够有效帮助SQL Server查询优化器获得最佳的数据访问途径。

  为了更直接地控制数据的行为,下面来搞个示例实战下,我们有一张Person表,里面有1万条数据左右。

  

  Id列原本是主键,但现在被撤掉了,因此选择性非常高,我们来看看如下SQL语句的执行计划与数据页读取情况:

  

  由执行计划来看,这是一个典型的书签查找,查询返回1条记录,有效地使用了索引。

  

  下面,我们来插入3000条Id为2的记录:

  DECLARE @i int;
  SET @i = 0;
  WHILE (@i < 3000)
  BEGIN
  INSERT INTO PersonTenThousand (Id,PId,Name) VALUES(2,3,'相同Id号')
  SET @i = @i + 1;
  END

  注意:由于SQL Server的索引更新机制,大于500条数据的情况下,插入数量要大于20%的情况下,才会自动更新索引。

  现在再来执行相同的语句以及查询计划:

  

  

  我们看到,由于索引的自动更新机制,执行计划改变了,SQL Server认为对于返回3000条记录,使用表扫描要优于执行3000次书签查找。

  下面,我们来重复一次,先删除原有的3000条Id为2的记录,这次我们先关闭索引统计再插入3000条记录。

  --关闭自动统计索引
  ALTER DATABASE DataExample SET AUTO_UPDATE_STATISTICS OFF

  

  

  我们看到,索引统计的不更新,导致SQL Server仍然使用原来的执行计划,进行了3000多次查找,逻辑读上升。

  这是为什么呢?因为统计不更新了,SQL Server并不知道Id=2多了3000条记录,还是以为Id=2的记录只有一条,因此就使用了索引进行书签查找。

  小结:过时的索引统计会导致SQL Server根据旧的统计执行计划,而实际上这些执行计划在数据更新后可能并不是最优的。因此,最好保持索引的自动更新。

 
 

索引列上的统计 <第一篇>的更多相关文章

  1. 非索引列上的统计 <第二篇>

    非索引列上的统计 有时候,可能在连接或过滤条件中的列上没有索引.即使对这种非索引列,如果查询优化器知道这些列的数据分布(统计),它也很可能做出最佳的选择. 除了索引上的统计,SQL Server可以在 ...

  2. UNIQUEIDENTIFIER列上的统计信息

    UNIQUEIDENTIFIER列上的统计信息非常有意思,在它上面有一些很令人讨厌的行为.我们来看下. 问题重现(The repro) 为了向你展示我们刚抱怨的行为,我用下列简单的表定义创建了一个数据 ...

  3. Windows系统CPU内存网络性能统计第一篇 内存

    最近翻出以前做过的Windows系统性能统计程序,这个程序可以统计系统中的CPU使用情况,内存使用情况以及网络流量.现在将其整理一下(共有三篇),希望对大家有所帮助. 目录如下: 1.<Wind ...

  4. oracle避免在索引列上使用NOT

    通常, 我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的 影响. 当ORACLE”遇到”NOT,他就会停止使用索引转而执行全表扫描. 举例: 低效: (这里,不使用索引) S ...

  5. 避免在WHERE条件中,在索引列上进行计算或使用函数,因为这将导致索引不被使用

    点击(此处)折叠或打开 --在sal列上创建非唯一索引 scott@TESTDB11>create index idx_emp1_sal on emp1(sal); Index created. ...

  6. oracle避免在索引列上使用IS NULL和IS NOT NULL

    避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引 .对于单列索引,如果列包含空值,索引中将不存在此记录. 对于复合索引,如果每个列都为空,索引中同样不存在此记录. 如果至少有一个列不为空 ...

  7. oracle避免在索引列上使用计算

    WHERE子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描. 举例: 低效: SELECT … FROM DEPT WHERE SAL * 12 > 25000; 高效: SE ...

  8. 这是我在word 2010上发布的第一篇文章

    1.设置word 2010,添加cnblogs帐户 配置参考链接 其中URL地址为: http://rpc.cnblogs.com/metaweblog/fariver,在cnblogs配置的最下方可 ...

  9. SQL Server 执行计划利用统计信息对数据行的预估原理二(为什么复合索引列顺序会影响到执行计划对数据行的预估)

    本文出处:http://www.cnblogs.com/wy123/p/6008477.html 关于统计信息对数据行数做预估,之前写过对非相关列(单独或者单独的索引列)进行预估时候的算法,参考这里. ...

随机推荐

  1. Window Ghosting(仍可拖动失去响应的窗口,因为我们真正的窗口已经让系统用Ghosting窗口替代了。使用IsHungAppWindow 探测)

    最近工作中遇到Window Ghosting这个问题, 感觉挺有意思,这里简单记录下.     在XP时代我们的程序没有响应后只能通过任务管理器强制杀掉,但是Vista之后情况变了, 我们仍然可以拖动 ...

  2. android 之 百度地图

    简介 百度地图Android定位SDK为基于移动客户端开发LBS应用提供基础定位能力. 功能介绍 功能介绍: 地图展示:包括2D图.卫星图.3D图地图展示. 地图操作:提供控制平移.缩放.底图旋转.变 ...

  3. jar包版本冲突,并且要保留两个版本都能使用

    问题:在做项目时,遇到jar版本冲突的问题,并且老代码依赖不能用新jar包代替,要保证功能不变须要保证两个jar都能使用 思路:使用runtime 的exec 方式另启线程运行,然后返回结果 解决: ...

  4. WPF多线程问题

    最近碰到这种多线程问题都是在WPF项目中. 1. 问题是这样.有个一主界面线程,然后background线程启动,这个background线程试图去修改主界面里面的数据. 造成死锁. 调用过程,主界面 ...

  5. mysql 从data文件恢复数据库

    安装在D:\mysql\mysql-5.6.24-winx64下的mysql 由于系统坏了,移到另外一台机器上启动 步骤如下 1.复制以前的mysql安装文件及data文件下:2.全新安装mysql3 ...

  6. js计算日期天数差-2013-9-26

    function daymath(sdate, edate) {             var startdate = sdate;             var enddate = edate; ...

  7. c++11 线程:让你的多线程任务更轻松

      介绍 本文旨在帮助有经验的Win32程序员来了解c++ 11线程库及同步对象 和 Win32线程及同步对象之间的区别和相似之处. 在Win32中,所有的同步对象句柄(HANDLE)是全局句柄.它们 ...

  8. C# 超级简单的Telnet (TcpClient)客户端

    基于Sockets 没什么好说的,代码说明了所有 using System; using System.Collections.Generic; using System.Linq; using Sy ...

  9. compass模块----Utilities----Sprites精灵图合图

    css雪碧图又叫css精灵或css sprite,是一种背景图片的拼合技术.使用css雪碧图,能够减少页面的请求数.降低图片占用的字节,以此来达到提升页面访问速度的目的.但是它也有令人诟病的地方,就是 ...

  10. URI和URL

    URI(uniform resource identifier),统一资源标识符,用来唯一的标识一个资源. URL(uniform resource locator),统一资源定位器,它是一种具体的U ...