SQL语句调优 - 索引上的数据检索方法

若是一张表上没有汇集索引,数据将会随机的顺序存放在表里。以dbo.SalesOrderDetail_TEST为例子。它的上面没有汇集索引,只有一个在SalesOrderID上的非汇集索引。因此表格的每一行记录,不会按照任何顺序,而是随意地存放在Hash里。这个时候若是用户想要找全部单价大于200的销售详细记录,要运行的语句会是:oop

SET STATISTICS  PROFILE ON 

SELECT SalesOrderDetailID , Unitprice
FROM SalesOrderDetail_test
WHERE UnitPrice > 200

因为表在UnitPrice上没有索引,因此SQL SERVER不得不对这个表从头至尾扫描一遍,把全部UnitPrice的值大于200的记录一个一个挑出来。性能

 

从执行计划里能够清楚地看出来SQL SERVER 这里作了一个表扫描(下图),后面会详细介绍如何获得和分析执行计划spa

 

若是这个表上有汇集索引,事情会怎么样呢?仍是刚才那张表作例子,先给它的值是惟一的字段 Unitprice上创建一个汇集索引。这样全部的数据都会按照汇集索引的顺序存储。3d

CREATE CLUSTERED INDEX  SalesOrderDetail_TEST_CL ON dbo.SalesOrderDetail_test (SalesOrderDetailID)

惋惜的是,查询条件Unitprice上没有索引,因此SQL SERVER仍是要把全部记录都扫描一遍。以下图code

与以前不一样的是,执行计划里的表扫描变成了汇集索引扫描。由于在有汇集索引的表上,数据是直接存放在索引的最底层的,因此要扫描整个表格的数据,就是把整个汇集索引扫描一遍。在这里,汇集索引扫描就至关于一个表扫描。所要用的时间和资源与表扫描没有什么差异。并非说这里有了”Index”这个字样,就说明执行计划比表扫描的有多大进步。固然反过来说,若是看到”Table Scan”的字样,就说明这个表格上没有汇集索引。对象

如今在 UnitPrice 上面建一个非汇集索引,看看状况会有什么变化blog

CREATE NONCLUSTERED INDEX  SalesOrderDetail_TEST_NCL_Price ON dbo.SalesOrderDetail_test (UnitPrice)

再次查询索引

SET STATISTICS  PROFILE ON 

SELECT SalesOrderDetailID , Unitprice
FROM SalesOrderDetail_test
WHERE UnitPrice > 200

 

在非汇集索引里,会为每条记录存储一份非汇集索引索引键的值和一份汇集索引索引键的值(在没有汇集索引的表格里,是RID值)。因此在这里,每条记录都会有一份 SalesOrderDetailID和UnitPrice记录,按照UnitPrice的顺序存放。再查询,就会看到此次的SQL SERVER不是扫描整个表,会根据新建的索引直接找到符合的记录的值。ci

可是光用UnitPrice创建在上的索引不能告诉咱们其它字段的值。若是在刚才那个查询里再增长几个字段返回,SQL SERVER 就要先在非汇集索引上找到全部UnitPrice大于200的记录,而后再根据SalesOrderDetailID的值找到存储在汇集索引上的详细数据。这个过程能够称为 “Bookmark Loopup”资源

SET STATISTICS  PROFILE ON

SELECT SalesOrderId,SalesOrderDetailID , Unitprice
FROM SalesOrderDetail_test with(index = SalesOrderDetail_TEST_NCL_Price)
WHERE UnitPrice > 200

         在SQL SERVER 2005之后,Bookmark Loopup 的动做用一个嵌套循环来完成。因此在执行计划里,能够看到SQL SERVR是先SEEK了非汇集索引,而后再用Clustered Index Seek 把须要的行找出来。这里的嵌套循环其实就是 Bookmark Loopup 以下图。

 

注:Bookmark Loopup就是汇集索引

在SQL SERVER里根据数据找寻目标的不一样和方法不一样。有下面几种状况。

结构

Scan

Seek

堆(没有汇集索引的表)

Tablescan

汇集索引

Clustered Index Scan

Clustered Index Seek

非汇集索引

Index Scan

Index Seek

 

若是在执行计划里看到这些动做,就应该可以知道SQL SERVER正在对哪一种对象在作什么样的操做。表扫描代表正在处理的表没有汇集索引,SQL SERVER正在扫描整张表。汇集索引扫描代表SQL SERVER正在扫描一张有汇集索引的表,可是也会是整表扫描。Index Scan代表SQL SERVER正在扫描一个非汇集索引。因为非汇集索引上通常只会有一小部分字段,因此这些虽然也是扫描,可是代价会比整表扫描要小不少。Clustered Index Seek 和Index Seek会比Scan 说明SQL SERVER正在利用索引结果检索目标数据。若是结果集只占表格总数据量的一小部分,Seek 会比Scan便宜不少,索引就起到了提升性能的做用。

了解这些是为之后读懂执行计划作基础。水平有限,暂时为这些吧。你们能够多多交流。

下一次会写统计信息的东西,可能会稍多一些。上述一语句均为上一次发博客的脚本为例。

相关文章
相关标签/搜索