有关SQL Server分布统计的问题

最近常被一些人问到关于SQL Server中统计的问题,这些问题是:

  • 是否需要关注数据库中统计的多少?
  • 统计对象使用多个空间

就执行SQL语句来说,查询优化器使用索引或列的分布统计信息来选择最佳的策略或计划;如果缺少统计信息或统计信息过期,性能会受到影响。在回答这些问题前,需要介绍一些关于分布统计的背景知识:什么是分布统计、其重要性、如何创建、更新、显示或查询。

 

分布统计的定义

在介绍之前,不得不推荐的一些关于Holger Schmeling写的一系列关于统计的文章,强烈建议仔细阅读,我认为是最有价值的。

简单地说,统计(包含索引或列中的数据分布的一种映射或直方图)用于选取最好的查询执行计划;当系统正常时,你不必担心这些,这么说的原因是他们是自动创建的,随着数据的变化也保持自动更新,如果查询优化器‘编译’查询时,如果没有找到可用的统计来判断表或索引中的数据分布状态,数据库会在需要时自动创建一个,例如当你在WHERE子句中使用列过滤或在某列上进行DISTINCT操作时。


下面我们一起来看一下统计对象的直方图(Histogram),直方图主要衡量数据集中每一个非重复值的发生次数,查询优化器根据统计对象的第一个键列的值计算出一个直方图,通常一个直方图最多有200个值。

查看统计的详细信息,可以使用如下的命令:

   1: DBCC SHOW_STATISTICS (Tab1, Stats_MyStatOnCol1)

执行结果如下:

1314-image001.png

 

从上面的输出结果,注意到数据分成三个部分:Header、密度向量、Historgram。

在Header部分,由一系列有用的值(这些也可以结合STA_HEADER参数使用DBCC SHOW_STATISTICS来获取)下面介绍在Header中包含的信息:

名称描述
Updated记录更新统计的时间,也可以使用STATS_DATE函数获取
Rows记录表或索引视图中总的行数
Rows Sampled采样的行数,如果此条数小于总的记录数,显示的直方图和密度值则基于采样行数
Steps直方图中的步值,每一个step表示一个范围值
Density由1/非重复值(第一键列)算出
Average key Length统计对象中键值的平均字节数
String Index表示统计对象包含字符汇总统计以提高基数估计的性能,如WHERE ProductName like ‘%bike%'
Filter ExpressionNULL表示非filtered统计,有关filtered谓词,参阅Filtered Index Design Guidelines,有关filtered统计,参阅Using Statistics to Improve Quer performance.
Unfiltered Rows应用Filter表达式前的表的行数,如果Filter Expression为空,则该值与Rows保持一致

 

对于密度向量,这里不进行介绍,查询优化器一般不使用此部分信息。

下面介绍直方图

 

image

下面对输出结果进行解释:

RANGE_HI_KEY: 每一个直方图中的键值,以第4行RANGE_HI_KEY为什么111的为例,代表的意思是范围从108(107-第3行)到111.

RANGE_ROWS:大于上一个RANGE_HI_KEY键值(107)并且小于当前RANGE_HI_KEY键值(111)的行数,例如:从108到110之间(不包括111),满足的行数有160行。

EQ_ROWS:等于RANGE_HI_KEY值的行数,如等于111的行有64个。

DISTINCT_RANGE_ROWS: 范围间内非重复行数,例如:从108到110之间,共有3条,即108、109、110。

AVG_RANGE_ROWS: 范围平均行数(RANGE_ROWS/DISTINCT_RANGE_ROWS),例如:第4行为例,其AVG行数为53.33333(160/3)。

 

要理解直方图的使用,我们通过一个简单的表作为示例,在该示例表上创建一些统计来分析查询优化器是如何使用这些统计的;我们首先创建一个表,接着在该表上创建统计,脚本如下:

   1: use tempdb
   2: GO
   3: IF OBJECT_ID('Itens') IS NOT NULL
   4:   DROP TABLE Itens
   5: GO
   6: CREATE TABLE dbo.Itens(Quantidade int NULL)
   7: GO
   8: CREATE STATISTICS Stats_Quantidade ON Itens(Quantidade)
   9: GO
  10: UPDATE STATISTICS Itens WITH ROWCOUNT = 50000, PAGECOUNT = 180
  11: GO
  12: UPDATE STATISTICS Itens Stats_Quantidade WITH STATS_STREAM = 0x01000000010...

由于这里使用了STATS_STREAM来设置统计,可以点击下载脚本来创建。

下面来看下表的直方图:

   1: DBCC SHOW_STATISTICS (Itens, Stats_Quantidade) WITH HISTOGRAM

image

接下来通过一些查询来看下执行计划。

示例一:(EQ_ROWS)

 

   1: SELECT * FROM Itens
   2: WHERE Quantidade = 107
   3: OPTION (RECOMPILE)

image

从执行计划可以看出,SQL Server根据WHERE子句的条件值107估计的行数为60,该数值对应直方图中RANGE_HI_KEY为107的EQ_ROWS。

示例二:(RANGE_ROWS+EQ_ROWS)

   1: SELECT * FROM Itens
   2: WHERE Quantidade <=107
   3: OPTION (RECOMPILE)

image

从执行计划中看出,查询优化器根据直方图中的行数进行条件筛选,对Quantidate<=107的行进行汇总:

image

说明:总行数=0+56+171+59+88+60=434,此数字与执行计划中“估计行数”一致。

 

示例三:(AVG_RANGE_ROWS)

假如,我们对条件值进行变化,如下:

   1: SELECT * FROM Itens
   2: WHERE Quantidade =108
   3: OPTION (RECOMPILE)

image

注意执行计划中红色圈注的部分,由于这次条件筛选的值108不在直方图中,故查询优化器使用AVG_RANGE_ROWS列来估计返回的行数,在本例中,在108到110之间的平均值为53.3333。

image

 

示例四:(RANGE_ROWS+EQ_ROWS+AVG_RANGE_ROWS)

   1: SELECT * FROM Itens
   2: WHERE Quantidade <=112
   3: OPTION (RECOMPILE)

image

本例与上面的示例二类似,不同的是,由于直方图中并不包含112这个值,故SQL Server需要把AVG_RANGE_ROWS(50.66667)添加至总和中,即:

image

说明:估计的行数=0+56+171+59+88+60+160+64+50.66667=708.667,此值与执行计划中的“估计行数”一致。

 

示例五:(RANGE_ROWS+EQ_ROWS+SPECIAL_AVG_RANGE_ROWS)

   1: SELECT * FROM Itens
   2: WHERE Quantidade <=113
   3: OPTION (RECOMPILE)
image

本例的查询与示例四很类似,不同的是,这次过滤的条件值为113,这对查询优化器来说是很容易判断要估计的行数,只再需对50.66667添加两次,原因是112和113都不在直方图中),故得出以下格式:

0+56+171+59+88+60+160+64+50.66667+50.66667=759.33334。

不过,查询优化器估计的值为744.857,那问题是它如何得到此值呢?

答案是:查询优化器汇总了两次43.42857,那查询优化器又是如何得到43.42857?

回答这个问题,查询优化器没有使用AVG_RANGE_ROWS列的值,而使用新的计算公式,即:

special_avg_range_rows = range_rows / ( distinct_range_rows + 1 ),根据直方图中第5行来计算:

304/(6+1) = 43.42857.

由此得出估计的行数公式:

0+56+171+59+88+60+160+64+43.42857+43.42857=744.85714

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/355374/viewspace-719120/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/355374/viewspace-719120/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: SQL Server中可以使用以下语句将数据的统计结果存储在统计表中: 1. 创建统计表: ``` CREATE TABLE [schema].[table] ( [name] NVARCHAR(128) NOT NULL, [stats_date] DATETIME NOT NULL, [modification_counter] BIGINT NOT NULL, [sampling_rate] FLOAT NOT NULL, [last_updated] DATETIME NOT NULL, [rows] BIGINT NOT NULL, [rows_sampled] BIGINT NOT NULL, [steps] INT NOT NULL, [density] FLOAT NOT NULL, [average_key_length] FLOAT NOT NULL, [string_index] BIT NOT NULL, [filter_definition] NVARCHAR(MAX) NULL ) ``` 2. 使用以下语句更新统计表: ``` UPDATE [schema].[table] SET [modification_counter] = [s].[modification_counter], [sampling_rate] = [s].[sampling_rate], [last_updated] = [s].[last_updated], [rows] = [s].[rows], [rows_sampled] = [s].[rows_sampled], [steps] = [s].[steps], [density] = [s].[density], [average_key_length] = [s].[average_key_length], [string_index] = [s].[string_index], [filter_definition] = [s].[filter_definition] FROM [schema].[table] [t] INNER JOIN sys.stats [s] ON [s].[object_id] = OBJECT_ID('[schema].[table]') AND [s].[name] = [t].[name] WHERE [t].[stats_date] < [s].[last_updated] ``` 3. 使用以下语句将统计信息插入到统计表中: ``` INSERT INTO [schema].[table] ( [name], [stats_date], [modification_counter], [sampling_rate], [last_updated], [rows], [rows_sampled], [steps], [density], [average_key_length], [string_index], [filter_definition] ) SELECT [name], GETDATE(), [modification_counter], [sampling_rate], [last_updated], [rows], [rows_sampled], [steps], [density], [average_key_length], [string_index], [filter_definition] FROM sys.stats WHERE [object_id] = OBJECT_ID('[schema].[table]') ``` ### 回答2: 在SQL Server中,统计表是用来存储数据的统计结果的。统计表包含了数据库中的各种统计信息,如表的行数、的数据分布、索引的选择性等。 要使用SQL Server将数据的统计结果存储在统计表中,我们可以执行以下相关语句: 1. 创建统计表:首先,我们需要创建一个用于存储统计信息的统计表。可以使用CREATE TABLE语句来创建一个包含统计信息字段的表,例如: CREATE TABLE statistics_table ( table_name VARCHAR(100), row_count INT, column_name VARCHAR(100), data_distribution VARCHAR(100), index_selectivity DECIMAL(10,2) ); 2. 插入统计信息:当我们想要存储数据的统计信息时,可以使用INSERT INTO语句将这些信息插入到统计表中。例如,我们可以使用以下语句将某个表的行数、名、数据分布和索引选择性插入到统计表中: INSERT INTO statistics_table (table_name, row_count, column_name, data_distribution, index_selectivity) SELECT 'customer_table', COUNT(*), 'customer_name', 'balanced', 0.75 FROM customer_table; 3. 更新统计信息:当数据库中的数据发生改变时,我们可能需要更新存储在统计表中的统计信息。可以使用UPDATE语句来更新统计表的相关数据。例如,我们可以使用以下语句更新某个表的行数: UPDATE statistics_table SET row_count = (SELECT COUNT(*) FROM customer_table) WHERE table_name = 'customer_table'; 通过使用以上语句,我们可以将SQL Server中数据的统计结果存储在统计表中,以供以后的分析和查询使用。这样可以提高查询性能和优化数据库设计。 ### 回答3: SQL Server将数据的统计结果存储在统计表中,是为了提高查询性能和优化执行计划。统计表是SQL Server数据库引擎中的一个系统对象,用于存储表、索引和统计信息,包括行数、唯一值的个数、数据分布等。 通过统计表,SQL Server可以根据实际的数据特征来选择最佳的执行计划,并进行查询优化。当SQL Server执行查询时,会根据查询条件选择合适的索引,并利用统计表中的统计信息来估计成本和选择合适的操作方式。这样可以显著减少查询所需的时间和资源消耗。 SQL Server更新统计表的方式有两种:自动更新和手动更新。自动更新是SQL Server根据一定的规则和策略来自动更新统计信息。例如,当插入、更新或删除操作导致统计信息过时时,SQL Server会自动更新统计表。手动更新是通过使用UPDATE STATISTICS语句强制手动更新统计信息。 通过使用UPDATE STATISTICS语句,我们可以选择性地更新某个表、索引或统计信息,以满足特定查询的需求。此外,还可以指定更新选项,如FULLSCAN、SAMPLE或RESAMPLE,以控制更新的方式和精度。 总之,SQL Server将数据的统计结果存储在统计表中可以提高查询性能和优化执行计划,从而提升数据库的整体性能和效率。通过自动更新和手动更新统计信息,可以保证统计表中的数据与实际数据的一致性,并满足不同查询的特定需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值