SQLServer统计信息理解
2015-11-10 19:25
411 查看
前言
Sqlserver 查询是基于开销查询的,在首次生成执行计划时,是基于多阶段的分析优化才确定出较好的执行计划。而这些开销的基数估计,是根据统计信息来确定的。统计信息其实就是对表的各个字段的总体数据进行分段分布,数据库默认都会自动维护。
表和视图都有统计信息,统计信息对象是根据索引或表列的列表创建的。当某列第一次最为条件查询时,将创建单列的统计信息。当创建索引时,将创建同名的统计信息。索引中,统计信息只统计首列,因此索引除了按首列排序存储数据外,其统计信息也是按首列计算统计的,所以索引设置时定义的第一列非常重要。每个统计信息对象都在包含一个或多个表列的列表上创建,并且包括显示值在第一列中的分布的直方图。
接下来了解统计信息吧~~ ^ ^
统计信息的查看:
可以看到,统计信息也是表的一种对象。
?
?
统计信息的属性:
右键统计信息,选择“属性”,可看到统计信息的设置和分布。
?
主要分为三部分,分别为“统计信息头部”,“密度向量”,“直方图”
1 统计信息头信息
2 密度信息
这里至于为什么会有3行,是因为【ProductID】为非聚集索引,【SalesOrderID,SalesOrderDetailID】为聚集索引,而每个非聚集索引中都包含有聚集索引的键值,所以这里的统计信息也出现了3个可选项。
当前统计信息 [All Density] 计算方法:
?
2 直方图
统计信息的重要性:
SQLServer中,在执行一个批处理语句时,关系引擎中的查询优化器会先估计生成较优的执行计划,执行执行器才安照此执行计划请求数据。即在生成执行计划期间,sqlserver是根据表中的统计信息进行行数估计,按照脚本语义来确定物理操作步骤生成执行计划,再按照该执行计划访问数据。而对于数据较大的表,按照统计信息估计的行数也常常不准确,这就是使查询使用了不准确的执行计划而比较慢。类似如:“参数嗅探”因传递参数值无法确定而估算错误;使用表变量不会有统计信息也不会估算行数。
?
如果查询日期范围在'2005-07-01'<ModifiedDate<='2005-08-01' ,看上图,查询返回的估计行数应该为896.7728(190.2021+706.5707)
?
估计行数为896.773,与统计信息的直方图的信息一致。其实就是根据直方图统计出来的,如果估计行数不准确,一定是统计信息没有正确的直方图信息,因此需要更新统计信息。有时候即使更新了统计信息,结果还是一样,因为数据量太大,估计数据不完全,看Rows Sampled可知道,因此也可以在更新统计信息时采用全表行数统计,但是这样扫描表数据也耗性能。即便如此,还是有些可能不一样,因为直方图的步长最多200,数据列中相同的和不同的差距太大,200段分布也有参差不齐的数据,不能使用更多步更详细的数据直方图。
统计信息的更新设置:
Sqlserver 默认自动维护统计信息,在数据库级别可以设置自动创建和更新统计信息的选项。
?
AUTO_CREATE_STATISTICS:
AUTO_CREATE_STATISTICS = ON 时,当将某列作为条件查询时,系统自动为每个条件列创建单列的统计信息。创建索引时也会自动创建相应的统计信息. 查询优化器通过使用 AUTO_CREATE_STATISTICS 选项创建统计信息时,统计信息名称以_WA
开头。
AUTO_UPDATE_STATISTICS:
AUTO_UPDATE_STATISTICS = ON 时,查询优化器将确定统计信息何时可能过期,然后在查询使用这些统计信息时更新它们。 统计信息将在插入、更新、删除或合并操作更改表或索引视图中的数据分布后过期。 查询优化器通过计算自最后统计信息更新后数据修改的次数并且将这一修改次数与某一阈值进行比较,确定统计信息何时可能过期。 该阈值基于表中或索引视图中的行数。查询优化器在编译查询和执行缓存查询计划前,检查是否存在过期的统计信息。 在编译某一查询前,查询优化器使用查询谓词中的列、表和索引视图确定哪些统计信息可能过期。
在执行缓存查询计划前,数据库引擎 确认该查询计划引用最新的统计信息。
AUTO_UPDATE_STATISTICS_ASYNC:
异步统计信息更新选项AUTO_UPDATE_STATISTICS_ASYNC 将确定查询优化器是使用同步统计信息更新还是异步统计信息更新。 默认情况下,异步统计信息更新选项被关闭,并且查询优化器以同步方式更新统计信息。 AUTO_UPDATE_STATISTICS_ASYNC 选项适用于为索引创建的统计信息对象、查询谓词中的单列以及使用 CREATE STATISTICS 语句创建的统计信息。统计信息更新可以是同步(默认设置)或异步的。 对于同步统计信息更新,查询将始终用最新的统计信息编译和执行;在统计信息过期时,查询优化器将在编译和执行查询前等待更新的统计信息。
对于异步统计信息更新,查询将用现有的统计信息编译,即使现有统计信息已过期。如果在查询编译时统计信息过期,查询优化器可以选择非最优查询计划。 在异步更新完成后编译的查询将从使用更新的统计信息中受益。
统计信息自动维护更新:
Sqlserver之所以自动维护统计信息,首先设置AUTO_UPDATE_STATISTICS=ON,sqlserver会在符合某条件时自动更新表中的统计信息。其中我们可以看到的,系统表sysindexes的列rowmodctr,它记录自上次更新统计信息后插入、删除、更新行的累计总次数。对于满足统计信息更新的条件,系统会自动更新。
SELECT name,rows,rowmodctrFROM sys.sysindexes
自动更新统计规则:
?表中行范围rows=0 行增长 rows>0行;
?表中行范围 0<rows<500行,只要变化的次数rowmodctr>500 ;
?表中行范围rows>500 行,只要变化的次数 rowmodctr>500+20%rows;
?临时表行数rows<6,只要变化的次数rowmodctr>6;
需要手动更新统计信息:
查询执行时间很长。
在升序或降序键列上发生插入操作。
在维护操作后。
?
?
?
?
?
?
?
?
?
?
现在行数602行,理论上超过601.2(501+501*0.2)行会更新,现在在更新一次,如果统计信息自动更新就对了
上图看到,真的更新了!所以这个条件是符合的:表中行范围rows>500行,只要变化的次数rowmodctr>500+20%rows;
统计信息更新总结如下:
?表中行范围rows=0 行增长 rows>0行(插入时不更新,更新删除行才更新);
?表中行范围 0<rows<500行,只要变化的次数rowmodctr>500 ;
?表中行范围rows>500 行,只要变化的次数 rowmodctr>500+20%rows;
?临时表行数rows<6,只要变化的次数rowmodctr>6(未测试);
创建索引时自动生成同名统计信息
非索引列在表有数据时首次作为条件查询时自动生成统计信息
对表首次插入多少数据都不自动更新统计信息
非键列的rows总是不更新(因为不存储数据)
统计信息相关操作:
?
Sqlserver 查询是基于开销查询的,在首次生成执行计划时,是基于多阶段的分析优化才确定出较好的执行计划。而这些开销的基数估计,是根据统计信息来确定的。统计信息其实就是对表的各个字段的总体数据进行分段分布,数据库默认都会自动维护。
表和视图都有统计信息,统计信息对象是根据索引或表列的列表创建的。当某列第一次最为条件查询时,将创建单列的统计信息。当创建索引时,将创建同名的统计信息。索引中,统计信息只统计首列,因此索引除了按首列排序存储数据外,其统计信息也是按首列计算统计的,所以索引设置时定义的第一列非常重要。每个统计信息对象都在包含一个或多个表列的列表上创建,并且包括显示值在第一列中的分布的直方图。
接下来了解统计信息吧~~ ^ ^
统计信息的查看:
可以看到,统计信息也是表的一种对象。
?
?
统计信息的属性:
右键统计信息,选择“属性”,可看到统计信息的设置和分布。
?
主要分为三部分,分别为“统计信息头部”,“密度向量”,“直方图”
1 统计信息头信息
列名 | 说明 |
Name | 统计信息对象的名称(IX_SalesOrderDetail_ProductID) |
Updated | 上一次更新统计信息的日期和时间(Mar 14 2012 1:14PM) |
Rows | 上次更新统计信息时表或索引视图中的总行数(121317)。如果筛选统计信息或者统计信息与筛选索引对应,该行数可能小于表中的行数 |
Rows Sampled | 用于统计信息计算的抽样总行数(121317)。如果 Rows Sampled < Rows,显示的直方图和密度结果则是根据抽样行估计的。 |
Steps | 直方图中的梯级数(200)。 每个梯级都跨越一个列值范围,后跟上限列值。 直方图梯级是根据统计信息中的第一个键列定义的。最大梯级数为 200。 |
Density | 计算公式为:1/统计信息对象第一个键列中的所有值(不包括直方图边界值)的 distinct values。(0.0078125) 查询优化器不使用此 Density 值,显示此值的目的是为了与 SQL Server 2008 之前的版本实现向后兼容。 |
Average Key Length | 统计信息对象中所有键列的每个值的平均字节数 (12 :3个int类型。 ProductID, SalesOrderID, SalesOrderDetailID) |
String Index | (NO)Yes 指示统计信息对象包含字符串摘要统计信息,以改进对使用 LIKE 运算符的查询谓词的基数估计;例如 WHERE ProductName LIKE '%Bike'。 字符串摘要统计信息与直方图分开存储,如果统计信息对象为char、varchar、nchar、nvarchar、varchar(max)、nvarchar(max)、text 或 ntext. 类型,则基于其第一个键列创建字符串摘要统计信息。 |
Filter Expression | 包含在统计信息对象中的表行子集的谓词。 NULL = 未筛选的统计信息。 |
Unfiltered Rows | 应用筛选表达式前表中的总行数(121317)。 如果 Filter Expression 为 NULL,则 Unfiltered Rows 等于 Rows。 |
列名 | 说明 |
All Density | Density 为 1/distinct values。 结果显示统计信息对象中各列的每个前缀的密度,每个密度显示一行。 非重复值是每个行前缀和列前缀的列值的非重复列表。 反映索引列的选择性(selectivity) "选择性"反映数据集里重复的数据量是多少,或者反过来说,值唯一的数据量有多少。如果一个字段的数据很少有重复,那么他的可选择性就比较高。比如身份证号,是不可重复的。哪怕对整个中国的身份记录做查询,代入一个身份证号码最多只会有一条记录返回,在这样的字段上的过滤条件,能够有效地过滤掉大量数据返回的结果集会比较小举个相反的例子:性别。所有人只有两种,非男即女。这个字段上的重复性就很高选择性就很低。一个过滤条件,最多只能过滤掉一半的记录SQL通过计算“选择性”,使得自己能够预测一个过滤条件做完后,大概能有多少记录返回 Density的定义是: density = 1/cardinality of index keys如果这个值小于0.1,一般讲这个索引的选择性比较高,如果大于0.1,他的选择性就不高了。 (参考《Microsoft sqlserver 企业级平台管理实践》) |
Average Length | 存储列前缀的列值列表的平均长度(以字节为单位)。 |
Columns | 为其显示 All density 和 Average length 的前缀中的列的名称 |
当前统计信息 [All Density] 计算方法:
?
2 直方图
列名 | 说明 |
RANGE_HI_KEY | 直方图梯级的上限列值。 列值也称为键值。(按ProductID 的范围分布) |
RANGE_ROWS | 其列值位于直方图梯级内(不包括上限)的行的估算数目。(2个ProductID 值之间有多少行) |
EQ_ROWS | 其列值等于直方图梯级的上限的行的估算数目。(等于当前行ProductID值的有多少行) |
DISTINCT_RANGE_ROWS | 非重复列值位于直方图梯级内(不包括上限)的行的估算数目。 (2个ProductID 值之间有多少不重复的键值ProductID) |
AVG_RANGE_ROWS | 重复列值位于直方图梯级内(不包括上限)的平均行数(如果 DISTINCT_RANGE_ROWS > 0,则为 RANGE_ROWS / DISTINCT_RANGE_ROWS)。 |
SQLServer中,在执行一个批处理语句时,关系引擎中的查询优化器会先估计生成较优的执行计划,执行执行器才安照此执行计划请求数据。即在生成执行计划期间,sqlserver是根据表中的统计信息进行行数估计,按照脚本语义来确定物理操作步骤生成执行计划,再按照该执行计划访问数据。而对于数据较大的表,按照统计信息估计的行数也常常不准确,这就是使查询使用了不准确的执行计划而比较慢。类似如:“参数嗅探”因传递参数值无法确定而估算错误;使用表变量不会有统计信息也不会估算行数。
?
如果查询日期范围在'2005-07-01'<ModifiedDate<='2005-08-01' ,看上图,查询返回的估计行数应该为896.7728(190.2021+706.5707)
?
估计行数为896.773,与统计信息的直方图的信息一致。其实就是根据直方图统计出来的,如果估计行数不准确,一定是统计信息没有正确的直方图信息,因此需要更新统计信息。有时候即使更新了统计信息,结果还是一样,因为数据量太大,估计数据不完全,看Rows Sampled可知道,因此也可以在更新统计信息时采用全表行数统计,但是这样扫描表数据也耗性能。即便如此,还是有些可能不一样,因为直方图的步长最多200,数据列中相同的和不同的差距太大,200段分布也有参差不齐的数据,不能使用更多步更详细的数据直方图。
统计信息的更新设置:
Sqlserver 默认自动维护统计信息,在数据库级别可以设置自动创建和更新统计信息的选项。
?
AUTO_CREATE_STATISTICS = ON 时,当将某列作为条件查询时,系统自动为每个条件列创建单列的统计信息。创建索引时也会自动创建相应的统计信息. 查询优化器通过使用 AUTO_CREATE_STATISTICS 选项创建统计信息时,统计信息名称以_WA
开头。
AUTO_UPDATE_STATISTICS:
AUTO_UPDATE_STATISTICS = ON 时,查询优化器将确定统计信息何时可能过期,然后在查询使用这些统计信息时更新它们。 统计信息将在插入、更新、删除或合并操作更改表或索引视图中的数据分布后过期。 查询优化器通过计算自最后统计信息更新后数据修改的次数并且将这一修改次数与某一阈值进行比较,确定统计信息何时可能过期。 该阈值基于表中或索引视图中的行数。查询优化器在编译查询和执行缓存查询计划前,检查是否存在过期的统计信息。 在编译某一查询前,查询优化器使用查询谓词中的列、表和索引视图确定哪些统计信息可能过期。
在执行缓存查询计划前,数据库引擎 确认该查询计划引用最新的统计信息。
AUTO_UPDATE_STATISTICS_ASYNC:
异步统计信息更新选项AUTO_UPDATE_STATISTICS_ASYNC 将确定查询优化器是使用同步统计信息更新还是异步统计信息更新。 默认情况下,异步统计信息更新选项被关闭,并且查询优化器以同步方式更新统计信息。 AUTO_UPDATE_STATISTICS_ASYNC 选项适用于为索引创建的统计信息对象、查询谓词中的单列以及使用 CREATE STATISTICS 语句创建的统计信息。统计信息更新可以是同步(默认设置)或异步的。 对于同步统计信息更新,查询将始终用最新的统计信息编译和执行;在统计信息过期时,查询优化器将在编译和执行查询前等待更新的统计信息。
对于异步统计信息更新,查询将用现有的统计信息编译,即使现有统计信息已过期。如果在查询编译时统计信息过期,查询优化器可以选择非最优查询计划。 在异步更新完成后编译的查询将从使用更新的统计信息中受益。
统计信息自动维护更新:
Sqlserver之所以自动维护统计信息,首先设置AUTO_UPDATE_STATISTICS=ON,sqlserver会在符合某条件时自动更新表中的统计信息。其中我们可以看到的,系统表sysindexes的列rowmodctr,它记录自上次更新统计信息后插入、删除、更新行的累计总次数。对于满足统计信息更新的条件,系统会自动更新。
SELECT name,rows,rowmodctrFROM sys.sysindexes
自动更新统计规则:
?表中行范围rows=0 行增长 rows>0行;
?表中行范围 0<rows<500行,只要变化的次数rowmodctr>500 ;
?表中行范围rows>500 行,只要变化的次数 rowmodctr>500+20%rows;
?临时表行数rows<6,只要变化的次数rowmodctr>6;
需要手动更新统计信息:
查询执行时间很长。
在升序或降序键列上发生插入操作。
在维护操作后。
?
?
?
?
?
?
?
?
?
?
现在行数602行,理论上超过601.2(501+501*0.2)行会更新,现在在更新一次,如果统计信息自动更新就对了
上图看到,真的更新了!所以这个条件是符合的:表中行范围rows>500行,只要变化的次数rowmodctr>500+20%rows;
统计信息更新总结如下:
?表中行范围rows=0 行增长 rows>0行(插入时不更新,更新删除行才更新);
?表中行范围 0<rows<500行,只要变化的次数rowmodctr>500 ;
?表中行范围rows>500 行,只要变化的次数 rowmodctr>500+20%rows;
?临时表行数rows<6,只要变化的次数rowmodctr>6(未测试);
创建索引时自动生成同名统计信息
非索引列在表有数据时首次作为条件查询时自动生成统计信息
对表首次插入多少数据都不自动更新统计信息
非键列的rows总是不更新(因为不存储数据)
统计信息相关操作:
?
相关文章推荐
- 20151110 oracle事务 redo undo
- MySQL的variables和status
- 数据库建表语句怎么写
- pl/sql 的 put和put_line区别
- 使用visio 2010建立sql server数据模型——手动画、利用逆向工程
- hive&mysql安装配置
- Oracle的tnsnames.ora配置(PLSQL Developer)
- mysql安装odbc
- oracle的内置函数
- mysql函数TIMESTAMPDIFF和FROM_UNIXTIME
- oracle用户创建及权限设置
- Oracle 通过sql profile为sql语句加hint
- 将指定SQL的执行计划从共享池删除的方法
- with as与hint materialize的使用
- 填坑 - 使用Entity Framework 6 + Sqlite进行DB first开发
- Oracle ORA-02020 : 过多的数据库链接
- windows平台下redis安装及配置文件介绍
- Redis在windows上的安装和配置
- Oracle自增列创建方法
- Node.js、express、mongodb 实现分页查询、条件搜索