索引列上的统计 <第一篇>
一、索引在查询优化中的角色
SQL Server的查询优化器是基于开销的优化器、它通过确认选择性、数据的唯一性以及过滤数据(通过WHERE或JOIN子句)所使用的列来决定最佳的数据访问机制。统计与索引一同存在,但是它们也作为断言的一部分存在于没有索引的列上。
作为谓词引用的列中数据分布的最新信息帮助优化器确定所使用的查询策略。在SQL Server中,这个信息以统计的形式维护,这对于基于开销的优化器创建一个有效的查询执行计划是很重要的。通过统计,优化器能做出返回结果集或中间结果集所花费时间的精确估计,从而确定最高效的操作。只要确定数据库已经进行了默认的统计设置,优化器就能尽其所能地动态确定有效的处理策略。而且,作为性能问题诊断时的安全性度量,应该确定自动统计维护历程正在按照预想工作。如果有必要,甚至手工控制统计的创建或维护。
二、索引列上的统计
索引的有效性完全取决于索引列上的统计。如果没有统计,SQL Server的基于开销的查询优化器将不能选择到使用索引最有效的方式。
SQL Server默认会自动创建索引键的统计,不管它是何时创建的。
我们知道,随着数据的变化,保持查询低开销的数据检索机制也会变化。例如,如果一个表对于某个列的值的选择性相当高为0.99,那么通过该列上的非聚集索引来检索匹配行是有意义的。但是如果表中数据变化,添加了大量该列有相同值的行选择性下降,那么使用这个非聚集索引就不再有意义。
SQL Server可以使一个索引上的统计随着索引列内容变化而更新。默认情况下,这个特性被开启,而且可以通过属性=》选项=》数据库的自动更新统计设置来开启或关闭。

更新统计消耗额外的CPU周期。为了优化和更新进行,SQL Server使用如下高效的算法来确定合适的更新统计时机:
- 当没有任何行的表得到一个行时;
- 当少于500行的表增加500行或更多行时;
- 当多于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根据旧的统计执行计划,而实际上这些执行计划在数据更新后可能并不是最优的。因此,最好保持索引的自动更新。
索引列上的统计 <第一篇>的更多相关文章
- 非索引列上的统计 <第二篇>
非索引列上的统计 有时候,可能在连接或过滤条件中的列上没有索引.即使对这种非索引列,如果查询优化器知道这些列的数据分布(统计),它也很可能做出最佳的选择. 除了索引上的统计,SQL Server可以在 ...
- UNIQUEIDENTIFIER列上的统计信息
UNIQUEIDENTIFIER列上的统计信息非常有意思,在它上面有一些很令人讨厌的行为.我们来看下. 问题重现(The repro) 为了向你展示我们刚抱怨的行为,我用下列简单的表定义创建了一个数据 ...
- Windows系统CPU内存网络性能统计第一篇 内存
最近翻出以前做过的Windows系统性能统计程序,这个程序可以统计系统中的CPU使用情况,内存使用情况以及网络流量.现在将其整理一下(共有三篇),希望对大家有所帮助. 目录如下: 1.<Wind ...
- oracle避免在索引列上使用NOT
通常, 我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的 影响. 当ORACLE”遇到”NOT,他就会停止使用索引转而执行全表扫描. 举例: 低效: (这里,不使用索引) S ...
- 避免在WHERE条件中,在索引列上进行计算或使用函数,因为这将导致索引不被使用
点击(此处)折叠或打开 --在sal列上创建非唯一索引 scott@TESTDB11>create index idx_emp1_sal on emp1(sal); Index created. ...
- oracle避免在索引列上使用IS NULL和IS NOT NULL
避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引 .对于单列索引,如果列包含空值,索引中将不存在此记录. 对于复合索引,如果每个列都为空,索引中同样不存在此记录. 如果至少有一个列不为空 ...
- oracle避免在索引列上使用计算
WHERE子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描. 举例: 低效: SELECT … FROM DEPT WHERE SAL * 12 > 25000; 高效: SE ...
- 这是我在word 2010上发布的第一篇文章
1.设置word 2010,添加cnblogs帐户 配置参考链接 其中URL地址为: http://rpc.cnblogs.com/metaweblog/fariver,在cnblogs配置的最下方可 ...
- SQL Server 执行计划利用统计信息对数据行的预估原理二(为什么复合索引列顺序会影响到执行计划对数据行的预估)
本文出处:http://www.cnblogs.com/wy123/p/6008477.html 关于统计信息对数据行数做预估,之前写过对非相关列(单独或者单独的索引列)进行预估时候的算法,参考这里. ...
随机推荐
- linux下的shell和脚本
1.各种Unix shell linux下的shell基本是从unix环境中的shell发展而来,贴一下wiki:其中我们常用的,可归类为Bourne Shell(/usr/bin/sh或/bin/s ...
- 关于Java集合的总结
(一)List: ArrayList 以数组实现.节约空间,但数组有容量限制.超出限制时会增加50%容量,用System.arraycopy()复制到新的数组,因此最好能给出数组大小的预估值.默认第一 ...
- phpStorm 各种快捷键
1. ctrl + shift + n: 打开工程中的文件(类似于eclipse中的ctrl+shift+R),目的是打开当前工程下任意目录的文件. 2. ctrl + j: 输出模板 3. ctrl ...
- VSCode
下载: 打开终端控制器 wget http://download.microsoft.com/download/0/D/5/0D57186C-834B-463A-AECB-BC55A8E466AE/V ...
- js获取url传递参数(转的,原作不详)
这里是一个获取URL带QUESTRING参数的JAVASCRIPT客户端解决方案,相当于asp的request.querystring,PHP的$_GET 函数: <Script languag ...
- 常用的js对象扩展方法
1. 字符串的replaceAll String.prototype.replaceAll = function(reallyDo, replaceWith, ignoreCase) { if (!R ...
- Makefile学习(一)变量
鉴于之前有一些了解,还有自己的学习习惯,我一上来就看Makefile的变量这一章.主要脉络是根据GNU make中文手册. 第六章:Makefile中的变量 6使用变量 定义:变量是一个名字,代表一个 ...
- QtWebkit2.2.0 HTML5.0支持情况
Canvas: 支持element, 2d context以及文本 解析规则:支持 HTML5 tokenizer/tree building, SVG in text/html, MathML ...
- lseek() 定位一个已经打开的文件
Lseek lseek()的作用是,设置文件内容的读写位置. 每个打开的文件都有一个"当前文件偏移量",是一个非负整数,用以度量从文件开始处计算的字节数.通常,读写操作都是从当前文 ...
- UIView的setNeedsLayout, layoutIfNeeded 和 layoutSubviews 方法之间的关系解释
转自:http://blog.csdn.net/meegomeego/article/details/39890385 layoutSubviews总结 ios layout机制相关方法 - (CGS ...