74

既然 aTable Scan和 aClustered 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
4

3 回答 3

82

在没有聚集索引的表(堆表)中,数据页没有链接在一起——因此遍历页需要查找索引分配映射

然而,聚簇表的数据页链接在一个双向链表中- 使顺序扫描更快一些。当然,作为交换,您需要处理在 、 和 上保持数据页有序INSERTUPDATE开销DELETE。但是,堆表需要对 IAM 进行第二次写入。

如果您的查询有一个RANGE运算符(例如:)SELECT * FROM TABLE WHERE Id BETWEEN 1 AND 100,那么一个聚簇表(有保证的顺序)会更有效 - 因为它可以使用索引页来查找相关的数据页。堆必须扫描所有行,因为它不能依赖排序。

而且,当然,聚集索引可以让您执行 CLUSTERED INDEX SEEK,这对于性能来说几乎是最佳的……没有索引的堆总是会导致表扫描。

所以:

  • 对于您选择所有行的示例查询,唯一的区别是聚集索引维护的双向链表。这应该使您的聚簇表比具有大量行的堆快一点。

  • 对于具有WHERE可以(至少部分)由聚集索引满足的子句的查询,由于排序,您将领先 - 因此您不必扫描整个表。

  • 对于聚集索引不满足的查询,您几乎可以......再次,唯一的区别是用于顺序扫描的双向链表。无论哪种情况,你都不是最理想的。

  • 对于INSERT, UPDATE, 和DELETE一个堆可能会或可能不会赢。堆不必维护顺序,但确实需要对 IAM 进行第二次写入。我认为相对性能差异可以忽略不计,但也非常依赖数据。

Microsoft 有一份白皮书,它将聚集索引与堆上的等效非聚集索引进行比较(与我上面讨论的不完全相同,但很接近)。他们的结论基本上是在所有表上放置一个聚集索引。我会尽力总结他们的结果(再次注意,他们实际上是在将非聚集索引与聚集索引进行比较 - 但我认为它相对具有可比性):

  • INSERT性能:由于堆需要第二次写入,聚集索引的优势约为 3%。
  • UPDATE性能:由于堆需要第二次查找,聚集索引的优势约为 8%。
  • DELETE性能:由于需要第二次查找以及需要从 IAM 中为堆进行第二次删除,聚集索引的优势约为 18%。
  • 单一SELECT性能:由于堆需要第二次查找,聚集索引的优势约为 16%。
  • 范围SELECT性能:由于堆的随机排序,聚集索引胜出约 29%。
  • concurrent INSERT:由于聚集索引的页面拆分,堆表在负载下胜出 30%。
于 2008-08-20T21:32:33.960 回答
4

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

Table Scan 逻辑和物理运算符从 Argument 列中指定的表中检索所有行。如果 WHERE:() 谓词出现在 Argument 列中,则仅返回满足该谓词的那些行。

于 2008-08-20T20:54:30.073 回答
-2

表扫描必须检查表的每一行。聚集索引扫描只需要扫描索引。它不会扫描表中的每条记录。这就是指数的意义所在。

于 2008-08-20T20:44:58.130 回答