题
由于两者都是 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
解决方案
在没有聚集索引的表(堆表)中,数据页不会链接在一起 - 因此遍历页需要 查找索引分配图.
然而,聚簇表有它的 以双向链表链接的数据页 - 使顺序扫描更快一些。当然,作为交换,您需要处理保持数据页有序的开销 INSERT
, UPDATE
, , 和 DELETE
. 。然而,堆表需要对 IAM 进行第二次写入。
如果您的查询有 RANGE
运算符(例如: SELECT * FROM TABLE WHERE Id BETWEEN 1 AND 100
),那么聚簇表(按保证的顺序)会更有效 - 因为它可以使用索引页来查找相关的数据页。堆必须扫描所有行,因为它不能依赖排序。
当然,聚集索引可以让您执行 CLUSTERED INDEX SEEK,这对于性能来说几乎是最佳的……没有索引的堆总是会导致表扫描。
所以:
对于选择所有行的示例查询,唯一的区别是聚集索引维护的双向链表。这应该使您的聚集表比具有大量行的堆快一点点。
对于带有 a 的查询
WHERE
如果您使用聚集索引可以(至少部分)满足的子句,那么您将因为排序而领先 - 因此您不必扫描整个表。对于不满足聚集索引的查询,您几乎是均匀的......再次,唯一的区别是用于顺序扫描的双向链表。无论哪种情况,你都不是最理想的。
为了
INSERT
,UPDATE
, , 和DELETE
堆可能会赢,也可能不会。堆不必维持顺序,但需要对 IAM 进行第二次写入。我认为相对性能差异可以忽略不计,但也相当依赖数据。
微软有一个 白皮书 它将聚集索引与堆上的等效非聚集索引进行比较(与我上面讨论的不完全相同,但很接近)。他们的结论基本上是在所有表上放置聚集索引。我将尽力总结他们的结果(再次注意,他们实际上是在此处将非聚集索引与聚集索引进行比较 - 但我认为它是相对可比的):
INSERT
表现:由于堆需要第二次写入,因此聚集索引领先约 3%。UPDATE
表现:由于堆需要进行第二次查找,因此聚集索引胜出约 8%。DELETE
表现:由于需要对堆进行第二次查找和从 IAM 进行第二次删除,因此聚集索引的胜率大约为 18%。- 单身的
SELECT
表现:由于堆需要进行第二次查找,因此聚集索引胜出约 16%。 - 范围
SELECT
表现:由于堆的随机排序,聚集索引胜出约 29%。 - 同时
INSERT
: :由于聚集索引的页分割,堆表在负载下胜出 30%。
其他提示
http://msdn.microsoft.com/en-us/library/aa216840(SQL.80).aspx
Clustered Index Scan 逻辑和物理运算符扫描 Argument 列中指定的聚集索引。当存在可选的 WHERE:() 谓词时,仅返回满足该谓词的行。如果 Argument 列包含 ORDERED 子句,则查询处理器已请求按聚集索引对行的排序顺序返回行的输出。如果 ORDERED 子句不存在,存储引擎将以最佳方式扫描索引(不保证输出被排序)。
http://msdn.microsoft.com/en-us/library/aa178416(SQL.80).aspx
表扫描逻辑和物理运算符从 Argument 列中指定的表中检索所有行。如果 WHERE:() 谓词出现在 Argument 列中,则仅返回满足该谓词的行。
表扫描必须检查表的每一行。聚集索引扫描只需要扫描索引即可。它不会扫描表中的每条记录。这确实是指数的意义所在。