由于Table Scan
和Clustered Index Scan
基本上扫描表中的所有记录,为什么聚集索引扫描应该更好?
作为一个例子 - 当有许多记录时,以下内容之间的性能差异是什么?:
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
答案 0 :(得分:77)
在没有聚簇索引(堆表)的表中,数据页没有链接在一起 - 因此遍历页面需要lookup into the Index Allocation Map。
然而,群集表具有data pages linked in a doubly linked list - 使顺序扫描更快一些。当然,作为交换,您需要处理在INSERT
,UPDATE
和DELETE
上按顺序处理数据页的开销。但是,堆表需要第二次写入IAM。
如果您的查询有RANGE
运算符(例如:SELECT * FROM TABLE WHERE Id BETWEEN 1 AND 100
),则群集表(保证顺序)会更高效 - 因为它可以使用索引页来查找相关数据页面。堆必须扫描所有行,因为它不能依赖于排序。
当然,聚集索引允许您执行CLUSTERED INDEX SEEK,这对性能来说非常优秀......没有索引的堆总会导致表扫描。
所以:
对于选择所有行的示例查询,唯一的区别是聚簇索引维护的双向链表。这应该使您的集群表比具有大量行的堆快一点。
对于具有WHERE
子句的查询,该子句可以(至少部分地)被聚集索引满足,由于排序,您将提前 - 因此您不必扫描整个表格。
对于群集索引不满意的查询,您甚至可以......再次,唯一的区别是顺序扫描的双向链表。在任何一种情况下,你都不是最理想的。
对于INSERT
,UPDATE
和DELETE
,堆可能赢得也可能不赢。堆不必维护顺序,但需要第二次写入IAM。我认为相对性能差异可以忽略不计,但也依赖于数据。
Microsoft有一个whitepaper,它将聚簇索引与堆上的等效非聚簇索引进行比较(与上面讨论的完全不同,但是关闭)。他们的结论基本上是在所有表上放置聚簇索引。我会尽力总结他们的结果(再次注意,他们真的在这里将非聚集索引与聚集索引进行比较 - 但我认为它相对可比):
INSERT
性能:由于堆需要第二次写入,聚簇索引会增加约3%。UPDATE
性能:由于堆需要第二次查找,聚集索引会赢得大约8%。DELETE
性能:由于需要进行第二次查找,并且需要从IAM进行第二次删除,因此聚簇索引会增加约18%。SELECT
性能:由于堆需要第二次查找,聚簇索引会赢得大约16%。SELECT
性能:由于堆的随机排序,聚簇索引增加了约29%。INSERT
:由于聚簇索引的页面拆分,堆表在负载下赢了30%。答案 1 :(得分:4)
http://msdn.microsoft.com/en-us/library/aa216840(SQL.80).aspx
聚簇索引扫描逻辑和物理运算符扫描Argument列中指定的聚簇索引。当存在可选的WHERE :()谓词时,仅返回满足谓词的那些行。如果Argument列包含ORDERED子句,则查询处理器已请求按照聚簇索引对其进行排序的顺序返回行的输出。如果ORDERED子句不存在,存储引擎将以最佳方式扫描索引(不保证输出被排序)。
http://msdn.microsoft.com/en-us/library/aa178416(SQL.80).aspx
表扫描逻辑和物理运算符从“参数”列中指定的表中检索所有行。如果WHAIL :()谓词出现在Argument列中,则仅返回满足谓词的那些行。
答案 2 :(得分:-2)
表扫描必须检查表的每一行。聚簇索引扫描只需要扫描索引。它不会扫描表中的每条记录。这确实是指数的重点。