教你如何看懂SQL Server查询计划(5)
列名
说明All density索引列前缀集的选择性(包括 EQ_ROWS)。注意:这个值越小就表示选择性越高。
如果这个值小于0.1,这个索引的选择性就比较高,反之,则表示选择性就不高了。Average length索引列前缀集的平均长度。Columns为其显示 All density 和 Average length 的索引列前缀的名称。
3. 第三个表格,数据分布的直方图,SQL Server就是靠它预估一些执行步骤的数据量。
列名 说明RANGE_HI_KEY每个组中的最大值。RANGE_ROWS每组数据组的估算行数,不包含最大值。EQ_ROWS为了能让您更好的理解这些数据,尤其是第三组,请看下图:
当时我在填充测试数据时,故意把CategoryId分为1到8(10是后来临时加的),每组填充了78条数据。所以【索引统计信息】的第三个表格的数据也都是正确的,也正是根据这些统计信息,SQL Server才能对每个执行步骤预估相应的数据量,从而影响Join之类的选择。当然了,在选择Join方式时,也要参考第二个表格中字段的选择性。SQL Server在为查询生成执行计划时,查询优化器将使用这些统计信息并结合相关的索引来评估每种方案的开销来选择最佳的查询计划。
再来个例子说明一下统计信息对于查询计划的重要性。首先多加点数据,请看以下代码:
declare @newCategoryId int;
insert into dbo.Categories (CategoryName) values(N'Test statistics');
set @newCategoryId = scope_identity();
declare @count int;
set @count = 0;
while( @count < 100000 )
begin
insert into Products (ProductName, CategoryID, Unit, UnitPrice, Quantity, Remark)
values( cast(newid() as nvarchar(50)), @newCategoryId, N'个', 100, @count +1, N'');
set @count = @count + 1;
end
go
update statistics Products;
go
再来看看索引统计信息:
再来看看同一个查询,但因为查询参数值不同时,SQL Server选择的执行计划:
select p.ProductId, t.Quantity
from Products as p left outer join [Order Details] as t on p.ProductId = t.ProductId
where p.CategoryId = 26; -- 26 就是最新产生的CategoryId,因此这个查询会返回10W条记录
select p.ProductId, t.Quantity
from Products as p left outer join [Order Details] as t on p.ProductId = t.ProductId
where p.CategoryId = 6; -- 这个查询会返回95条记录
从上图可以看出,由于CategoryId的参数值不同,SQL Server会选择完全不同的执行计划。统计信息重要性在这里体现的很清楚吧。
创建统计信息后,数据库引擎对列值(根据这些值创建统计信息)进行排序,并根据这些值(最多 200 个,按间隔分隔开)创建一个“直方图”。直方图指定有多少行精确匹配每个间隔值,有多少行在间隔范围内,以及间隔中值的密度大小或重复值的发生率。
SQL Server 2005 引入了对 char、varchar、varchar(max)、nchar、nvarchar、nvarchar(max)、text 和 ntext 列创建的统计信息收集的其他信息。这些信息称为“字符串摘要”,可以帮助查询优化器估计字符串模式中查询谓词的选择性。查询中有 LIKE 条件时,使用字符串摘要可以更准确地估计结果集大小,并不断优化查询计划。这些条件包括诸如 WHERE ProductName LIKE '%Bike' 和 WHERE Name LIKE '[CS]heryl' 之类的条件。
既然【索引统计信息】这么重要,那么它会在什么时候生成或者更新呢?事实上,【索引统计信息】是不用我们手工去维护的,SQL Server会自动去维护它们。而且在SQL Server中也有个参数来控制这个更新方式:
统计信息自动功能工作方式
创建索引时,查询优化器自动存储有关索引列的统计信息。另外,当 AUTO_CREATE_STATISTICS 数据库选项设置为 ON(默认值)时,数据库引擎自动为没有用于谓词的索引的列创建统计信息。
随着列中数据发生变化,索引和列的统计信息可能会过时,从而导致查询优化器选择的查询处理方法不是最佳的。例如,如果创建一个包含一个索引列和 1,000 行数据的表,每一行在索引列中的值都是唯一的,则查询优化器将把该索引列视为收集查询数据的好方法。如果更新列中的数据后存在许多重复值,则该列不再是用于查询的理想候选列。但是,查询优化器仍然根据索引的过时分布统计信息(基于更新前的数据),将其视为好的候选列。