由SQL Server 2005收集的统计信息
SQL Server 2005在表级别维护以下信息。这些信息并不属于统计信息对象,而是SQL Server 2005在某些情况下用来进行查询成本估算的。
• 表或索引的行数(sys.sysindexes表的rows列)
• 表或索引占用的页面数(sys.sysindexes表的dpages列)
SQL Server 2005收集关于表中列的下述统计信息,并存储在一个统计信息对象中(statblob):
• 统计信息收集的时间。
• 用于生成直方图和密度信息的行数(将在下面讲解)。
• 平均键的长度。
• 单列直方图,包含了步数。
• 字符串摘要(如果某一列含有字符串信息)。如果一个统计信息对象包含了字符串摘要,那么DBCC SHOW_STATISTICS输出就会包含“String Index”列,并且该列的值为YES。
一个直方图是给定列的最多200个值的集合。给定列的所有值或抽样值会被排序;排序后的序列最多被划分为199个间隔,以便获得最有效的统计信息。间隔的大小通常是不等的。下面的值或足以派生这些值的信息被存储在直方图的每一步中。
SQL Server 2005只能为单列,或者多列统计信息对象中的第一列创建直方图。
SQL Server 2005通过三步从已排序的一组列值中创建直方图:
• 初始化直方图:在第一步,依次处理以排序集中第一个值作为起点的每个值,最多收集200个RANGE_HI_KEY, EQ_ROWS, RANGE_ROWS以及DISTINCT_RANGE_ROWS(在这一步中,RANGE_ROWS和DISTINCT_RANGE_ROWS始终为零)。当所有输入都被用尽,或者已经找到了200个值,第一步就结束了。
• 使用桶合并进行扫描:按照排序方式处理统计信息中首列的其余列值;每个值要么被添加到最后一个区间,要么被添加到一个新区间(由于输入的值已经排序,因此允许这样做)。如果创建了一个新区间,现有相邻的一对区间将被合并到一个区间。选取相邻的一对区间是为了将信息损失的程度降到最低。整个过程当所有区间合并完成后步数依然是200。该方法是基于maxdiff直方图的一种变形方法。
• 合并直方图:在第三步,如果信息损失的数量不十分明显,就有更多的区间被合并。因此,即使列中唯一值的数目超过了200,那么直方图的步数也可能少于200。
如果通过抽样来生成直方图,那么 RANGE_ROWS、EQ_ROWS、DISTINCT_RANGE_ROWS 和 AVG_RANGE_ROWS的值将为估计值,因此它们不必都是整数。
密度是给定的一列或组合列上关于重复项数目的信息,其计算公式为1/(唯一值数目)。当在一个等值判断表达式中使用了某一列时,就会使用从直方图导出的密度信息来估算满足条件的行数。还可以使用直方图来估算非等值选择判断、连接以及其它操作的选择性。
除了包含用于显示统计信息收集时间的时间戳、表中的行数、为生成直方图而抽样的行数、密度信息和平均的键长度、直方图本身以外,在单列统计信息中还包含了统计信息列集中组成前缀的每一组列的All density值。这些信息显示在DBCC SHOW_STATISTICS输出的第二个结果集中。All density 1/(前缀列集中唯一值得数目)。下一部分将给出相关的一个示例。
注意:dbcc show_statistics返回结果的首行中包含的密度值是所有抽样值的密度而不是RANGE_HI_KEY的密度。RANGE_HI_KEY通常是数据分布中出现频率较高的值。因此该命令所显示的密度值为那些出现频率不高的列值提供了潜在的有价值的信息。
在组合列上创建的多列统计信息包括:统计信息定义中首列的直方图,首列的密度值,以及每个前缀组合列(单独包括首列)的密度值。每组多列统计信息(一个直方图加上两个或多个密度值)都存储在一个statblob中,再加上上次更新统计信息的时间戳、用于生成统计信息的抽样行数、直方图的步数和平均键长度。只包含首列的字符串摘要,如果首列中含有字符型数据。
使用sp_helpindex和sp_helpstats来显示特定表上所有可用的统计信息。sp_helpindex列出表上所有的索引,而sp_helpstats列出表上所有的统计信息。每个索引都含有索引列的统计信息。使用CREATE STATISTICS命令创建的统计信息与在同一列上使用CREATE INDEX命令创建的统计信息是等价的。唯一不同的是CREATE STATISTICS命令默认使用抽样而CREATE INDEX则使用fullscan收集统计信息,因为创建索引时无论如何都必须处理所有的行。
创建和显示统计信息:示例
下面的例子说明如何自动和手动的创建统计信息,以及如何列表和显示关于统计信息的相关资料。示例中给出了某些命令但不是所有的命令的运行结果;如果某个SQL Server 2005命令的输出结果对于阐述统计信息的行为很有用,那么该结果就显示出来。您可以自己运行这个示例来查看完整的输出。
USE tempdb
GO
-- 清理以前运行脚本生成的对象
IF object_id(N'Person.Contact','U') IS NOT NULL
DROP TABLE Person.Contact
GO
IF EXISTS (SELECT * FROM sys.schemas WHERE name = N'Person')
DROP SCHEMA Person
GO
-- 创建示例的schema和表
CREATE SCHEMA Person
GO
CREATE TABLE Person.Contact(
FirstName nvarchar(60),
LastName nvarchar(60),
Phone nvarchar(15),
Title nvarchar(15)
)
GO
-- 加工表中的行
INSERT INTO Person.Contact
VALUES(N'James',N'Smith',N'425-555-1234',N'Mr')
INSERT INTO Person.Contact
VALUES(N'James',N'Andersen',N'425-555-1111',N'Mr')
INSERT INTO Person.Contact
VALUES(N'James',N'Andersen',N'425-555-3333',N'Mr')
INSERT INTO Person.Contact
VALUES(N'Christine',N'Williams',N'425-555-0000',N'Dr')
INSERT INTO Person.Contact
VALUES(N'Susan',N'Zhang',N'425-555-2222',N'Ms')
GO
-- 显示在Person.Contact表上还不存在统计信息
sp_helpstats N'Person.Contact', 'ALL'
GO
-- 在LastName列上隐式地创建统计信息
SELECT * FROM Person.Contact WHERE LastName = N'Andersen'
GO
-- 显示在LastName列上自动创建的统计信息
sp_helpstats N'Person.Contact', 'ALL'
GO
结果:
-- 创建索引,这将同时创建统计信息
CREATE NONCLUSTERED INDEX Phone on Person.Contact(Phone)
GO
-- 显示创建索引时会同时创建相关的统计信息
sp_helpstats N'Person.Contact', 'ALL'
GO
结果:
-- 在firstname和lastname列上创建统计信息
CREATE STATISTICS FirstLast ON Person.Contact(FirstName,LastName)
GO
-- 显示表上现在有三个统计信息对象
sp_helpstats N'Person.Contact', 'ALL'
GO
结果:
-- 显示LastName列的统计信息
DBCC SHOW_STATISTICS (N'Person.Contact', LastName)
GO
结果:
统计对象的标题信息:
-- If you take the name of the statistics object displayed by
-- the command above and subsitute it in as the second argument of
-- DBCC SHOW_STATISTICS you can form a command like the following one
--(the exact name of the automatically created statistics object
-- will typically be different for you).
DBCC SHOW_STATISTICS (N'Person.Contact', _WA_Sys_00000002_2D7CBDC4)
-- Executing the above command illustrates that you can show statistics by
-- column name or statistics object name.
GO
-- The following displays multi-column statistics. Notice the two
-- different density groups for the second rowset in the output.
DBCC SHOW_STATISTICS (N'Person.Contact', FirstLast)
结果(仅第二个结果集)
列集的前缀以及相关的密度和长度:
如果希望看到一张大型表的完整生成的直方图,运行下面的命令:
USE AdventureWorks
-- 清理以前运行脚本产生的对象
IF EXISTS (SELECT * FROM sys.stats
WHERE object_id = object_id('Sales.SalesOrderHeader')
AND name = 'TotalDue')
DROP STATISTICS Sales.SalesOrderHeader.TotalDue
GO
CREATE STATISTICS TotalDue ON Sales.SalesOrderHeader(TotalDue)
GO
DBCC SHOW_STATISTICS(N'Sales.SalesOrderHeader', TotalDue)
[