表扫描和聚簇索引扫描有什么区别?
由于“ Table Scan
和“ Clustered Index Scan
扫描表中的所有logging,为什么聚簇索引扫描会更好?
举个例子 – 当有很多logging时,下面的性能差别是什么?
declare @temp table( SomeColumn varchar(50) ) insert into @temp select 'SomeVal' select * from @temp ----------------------------- declare @temp table( RowID int not null identity(1,1) primary key, SomeColumn varchar(50) ) insert into @temp select 'SomeVal' select * from @temp
在没有聚集索引(堆表)的表中,数据页面没有链接在一起 – 因此遍历页面需要查找索引分配映射 。
然而,一个聚集表中,它的数据页是链接在一个双向链表中的 – 使得顺序扫描速度更快一些。 当然,作为交换,你有处理在INSERT
, UPDATE
和DELETE
保持数据页顺序的开销。 但是,堆表需要第二次写入IAM。
如果你的查询有一个RANGE
运算符(例如: SELECT * FROM TABLE WHERE Id BETWEEN 1 AND 100
),那么一个聚集表(保证顺序)会更有效率 – 因为它可以使用索引页来find相关的数据网页。 堆将不得不扫描所有的行,因为它不能依靠sorting。
而且,当然,聚集索引可以让你做一个CLUSTERED INDEX SEEK,这对于性能来说是非常理想的…没有索引的堆总是会导致表扫描。
所以:
-
对于你select所有行的示例查询,唯一的区别是聚集索引维护的双向链表。 这应该使你的聚簇表比一个有大量行的堆快一点点。
-
对于带有
WHERE
子句的查询,可以(至less部分)通过聚集索引满足要求,因为sorting,所以您将不得不提前扫描整个表。 -
对于一个不被聚集索引满足的查询,你几乎就是……唯一的区别就是顺序扫描的双向链表。 无论如何,你都不是最理想的。
-
对于
INSERT
,UPDATE
和DELETE
,堆可能赢或不赢。 堆不必维持顺序,但需要再次写入IAM。 我认为相对的性能差异可以忽略不计,但也依赖于漂亮的数据。
微软有一个白皮书 ,它将聚簇索引与堆上等价的非聚簇索引进行比较(与上面讨论的不完全相同,但是很接近)。 他们的结论基本上是在所有的表格上加上一个聚集索引。 我会尽我所能来总结他们的结果(再一次,请注意,他们真的在这里比较非聚集索引和聚集索引 – 但我认为它是相对可比的):
-
INSERT
性能:聚簇索引由于堆所需的第二次写入而赢得大约3%。 -
UPDATE
性能:聚簇索引由于堆的第二次查找而赢得大约8%。 -
DELETE
性能:聚簇索引由于需要第二次查找而赢得大约18%,并且需要从IAM中为堆进行第二次删除。 - 单一
SELECT
性能:聚簇索引由于堆所需的第二次查找而赢得大约16%。 - 范围
SELECT
性能:聚簇索引由于堆的随机sorting而赢得大约29%。 - 并发
INSERT
:由于聚簇索引的页面拆分,堆表在负载下获胜30%。
http://msdn.microsoft.com/en-us/library/aa216840(SQL.80).aspx
“群集索引扫描”逻辑和物理运算符将扫描“参数”列中指定的聚簇索引。 当存在一个可选的WHERE :()谓词时,只有那些满足谓词的行被返回。 如果参数列包含ORDERED子句,则查询处理器已经请求按照聚集索引对其进行sorting的顺序返回行的输出。 如果ORDERED子句不存在,存储引擎将以最佳方式扫描索引(不保证输出被sorting)。
http://msdn.microsoft.com/en-us/library/aa178416(SQL.80).aspx
“表扫描”逻辑和物理运算符从“参数”列中指定的表中检索所有行。 如果WHERE :()谓词出现在参数列中,则只返回满足谓词的那些行。
表扫描必须检查表的每一行。 聚簇索引扫描只需要扫描索引。 它不扫描表中的每个logging。 这实际上就是指数的重点。