Sql Server 会有以下方法来查找您需要的数据记录:
1. 【Table Scan】:遍历整个表,查找所匹配的记录行。这个操作将会一行一行的检查,当然,效率也是最差的。
2. 【Index Scan】:根据索引,从表中过滤出来一部分记录,再查找所匹配的记录行,显示比第一种方式的查找范围要小,因此比【Table Scan】要快。
3. 【Index Seek】:根据索引,定位(获取)记录的存放位置,然后取得记录,因此,比起前二种方式会更快。
4. 【Clustered Index Scan】:和【Table Scan】一样。注意:不要以为这里有个Index,就认为不一样了。 其实它的意思是说:按聚集索引来逐行扫描每一行记录,因为记录就是按聚集索引来顺序存放的。 而【Table Scan】只是说:要扫描的表没有聚集索引而已,因此这二个操作本质上也是一样的。
5. 【Clustered Index Seek】:直接根据聚集索引获取记录,最快! 所以,当发现某个查询比较慢时,可以首先检查哪些操作的成本比较高,再看看那些操作是查找记录时, 是不是【Table Scan】或者【Clustered Index Scan】,如果确实和这二种操作类型有关,则要考虑增加索引来解决了。 不过,增加索引后,也会影响数据表的修改动作,因为修改数据表时,要更新相应字段的索引。所以索引过多,也会影响性能。 还有一种情况是
某个字段用0或者1这二种情况分开来保存了,分表或者分区都是不错的选择。
由于对于复杂查询,估计可能有很大的误差,因此如果中间结果比预期的大得多,则处理中
回到【SQL Server Management Studio】,输入以下语句,然后执行。
set statistics profile on
select * from XXX
可以从图片上看到,执行查询后,它能反映更多的信息,而且尤其在比较复杂的查询时,可能看起来更容易,因为对于复杂的查询,【执行计划】的步骤太多,图形方式会造成图形过大,不容易观察。 而且这张执行过程表格能反映2个很有价值的数据(前二列)。 还是来看看这个【执行过程表格】吧。我来挑几个重要的说一下。
【Rows】:表示在一个执行步骤中,所产生的记录条数。(真实数据,非预期)
【Executes】:表示某个执行步骤被执行的次数。(真实数据,非预期)
【Stmt Text】:表示要执行的步骤的描述。
【EstimateRows】:表示要预期返回多少行数据。 在这个【执行过程表格】中,对于优化查询来说,我认为前三列是比较重要的。对于前二列,我上面也解释了,意思也很清楚。 前二列的数字也大致反映了那些步骤所花的成本,对于比较慢的查询中,应该留意它们。
【Stmt Text】会告诉你每个步骤做了什么事情。对于这种表格,它所要表达的其实是一种树型信息(一行就表示在图形方式下的一个节点), 所以,我建议从最内层开始去读它们。它所表达的执行过程。
第5行:【Clustered Index Seek(OBJECT:([MyNorthwind].[dbo].[Customers].[PK_Customers]), SEEK:([MyNorthwind].[dbo].[Customers].[CustomerID]=[MyNorthwind].[dbo].[Orders].CustomerID]) ORDERED FORWARD)】, 意思是说,SqlServer在对表Customers做Seek操作,而且是按照【Clustered Index Seek】的方式,对应的索引是【PK_Customers】,seek的值来源于[Orders].[CustomerID]
第4行:【Clustered Index Scan(OBJECT:([MyNorthwind].[dbo].[Orders].[PK_Orders]), WHERE:([MyNorthwind].[dbo].[Orders].[OrderDate]>='2010-12-01 00:00:00.000' AND [MyNorthwind].[dbo].[Orders].[OrderDate]<'2011-12-01 00:00:00.000'))】, 意思是说,SqlServer在对表Customers做Scan操作,即:最差的【表扫描】的方式,原因是,OrderDate列上没有索引,所以只能这样了。
第3行:【Nested Loops(Left Outer Join, OUTER REFERENCES:([MyNorthwind].[dbo].[Orders].[CustomerID]))】, 意思是说,SqlServer把第5行和第4行产生的数据用【Nested Loops】的方式联接起来,其中Outer表是Orders,要联接的匹配操作也在第5行中指出了。
第2行:【Compute Scalar(DEFINE:([Expr1006]=isnull([MyNorthwind].[dbo].[Customers].[CustomerName],N'')))】, 意思是说,要执行一个isnull()函数的调用。具体原因请参考本文前部分中给出视图定义代码。
第1行:【SELECT [v].[OrderID],[v].[CustomerID],[v].[CustomerName],[v].[OrderDate],[v].[SumMoney],[v].[Finished] FROM [OrdersView] [v] WHERE [v].[OrderDate]>=@1 AND [v].[OrderDate]<@2】, 通常第1行就是整个查询,表示它的返回值。
显示查询最佳化统计资料
dbcc show_statistics (Products, IX_CategoryID)
统计信息的作用:
1、index建立后,优化器是否使用该index,优化器需要借助一些统计信息来做判断
2、根据统计信息,预估采用嵌套循环连接,合并连接, 哈希连接等哪一个连接
3、根据统计信息判断表的估计最佳的成本(最佳的执行顺序)
ALTER DATABASE[Sfis] SET AUTO_CREATE_STATISTICS ON --启用自动统计信息创建功能
ALTER DATABASE[Sfis] SET AUTO_UPDATE_STATISTICS ON/OFF --(自动更新统计信息开关)
update statistics Sfis.dbo.Products --更新统计
再来看看命令的结果,它有三个表格组成:
1. 第一个表格,它列出了这个索引统计信息的主要信息。 列名 说明 Name 统计信息的名称。 Updated 上一次更新统计信息的日期和时间。 Rows 表中的行数。
Rows Sampled 统计信息的抽样行数。 Steps 数据可分成多少个组,与第三个表对应。 Density 第一个索引列前缀的选择性(不包括 EQ_ROWS)。 Average key length 所有索引列的平均长度。 String Index 如果为“是”,则统计信息中包含字符串摘要索引,以支持为 LIKE 条 件估算结果集大小。仅适用于 char、varchar、nchar和 nvarchar、varchar(max)、nvarchar(max)、text 以及 ntext 数据类型的前导列。
2. 第二个表格,它列出各种字段组合的选择性,数据越小表示重复越性越小,当然选择性也就越高。 列名 说明 All density 索引列前缀集的选择性(包括 EQ_ROWS)。注意:这个值越小就表示选择性越高。 如果这个值小于0.1,这个索引的选择性就比较高,反之,则表示选择性就不高了。 Average length 索引列前缀集的平均长度。 Columns 为其显示 All density 和 Average length 的索引列前缀的名称。
3. 第三个表格,数据分布的直方图,SqlServer就是靠它预估一些执行步骤的数据量。 列名 说明 RANGE_HI_KEY 每个组中的最大值。 RANGE_ROWS 每组数据组的估算行数,不包含最大值。 EQ_ROWS 每组数据组中与最大值相等的行的估算数目。 DISTINCT_RANGE_ROWS 每组数据组中的非重复值的估算数目,不包含最大值。 AVG_RANGE_ROWS 每组数据组中的重复值的平均数目,不包含最大值,计算公式: RANGE_ROWS / DISTINCT_RANGE_ROWS for DISTINCT_RANGE_ROWS > 0