表扫描和聚集索引扫描之间有什么区别?


70

由于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

Answers:


78

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

但是,群集表将其数据页链接在双链表中-使顺序扫描的速度更快。当然,作为交换,你必须处理保持数据页顺序的开销INSERTUPDATEDELETE。但是,堆表需要第二次写入IAM。

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

而且,当然,聚集索引使您可以执行聚集索引SEEK,这对于性能而言是非常理想的……没有索引的堆将始终导致表扫描。

所以:

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

  • 对于具有WHERE可被聚簇索引满足(至少部分满足)的子句的查询,您将因顺序而出名-因此您不必扫描整个表。

  • 同样,对于聚集索引无法满足的查询,您甚至可以...甚至,唯一的区别是用于顺序扫描的双链表。无论哪种情况,您都不理想。

  • 对于INSERTUPDATEDELETE一个堆可能会或可能不会赢。堆不必维护顺序,但确实需要第二次写入IAM。我认为相对性能差异可以忽略不计,但还取决于数据。

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

  • INSERT 性能:由于堆需要第二次写入,因此聚集索引的获胜率约为3%。
  • UPDATE 性能:由于需要对堆进行第二次查找,因此聚集索引的获胜率约为8%。
  • DELETE 性能:由于需要对IAM进行第二次查找和对堆进行第二次删除,因此聚集索引的获胜率约为18%。
  • 单一SELECT性能:由于需要对堆进行第二次查找,因此聚集索引的赢率约为16%。
  • 范围SELECT性能:由于对堆的随机排序,聚集索引的获胜率约为29%。
  • 并发INSERT:由于聚集索引的页面拆分,堆表在负载下胜出30%。

2
今天,这个问题浮现在我的脑海。感谢@Terrapin提出的问题,也感谢@Marc回答得这么好!
2011年

2
MS考试70461查询Microsoft SQL Server 2012-第15章第1课有深入的探讨。
Yevgraf Andreyevich Zhivago,2015年

我似乎无法获得您的以下陈述所表明的预期提升:“对于具有WHERE子句的查询(至少可以部分地由聚簇索引满足),您将因排序而出类拔萃-因此您不必扫描整个表格。” 我有一千万行的表。无论我是否对Id拥有聚集索引,从客户的Id> X的SELECT Id的执行时间都相同。怎么来的?我可以看到它如何从表扫描变为聚集索引扫描。
Mattias Nordqvist 2015年

2
@MattiasNordqvist-如果您只是在看时间,那您做错了。由于缓存,并发访问,CPU与磁盘时间等原因,仅按时间对MS-SQL进行性能调整是很困难的。查看SET STATISTICS IO ON来检查您的磁盘读取,这将来自增强。其次,它取决于返回的行数-如果百分比足够高,优化器可以考虑选择一个read +过滤器。
Mark Brackett

4

http://msdn.microsoft.com/zh-CN/library/aa216840(SQL.80).aspx

聚集索引扫描逻辑和物理操作员将扫描“参数”列中指定的聚集索引。当存在可选的WHERE :()谓词时,仅返回满足该谓词的那些行。如果Argument列包含ORDERED子句,则查询处理器已请求按聚集索引对行进行排序的顺序返回行的输出。如果不存在ORDERED子句,则存储引擎将以最佳方式扫描索引(不保证对输出进行排序)。

http://msdn.microsoft.com/zh-CN/library/aa178416(SQL.80).aspx

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


-2

表扫描必须检查表的每一行。聚集索引扫描仅需要扫描索引。它不会扫描表中的每条记录。确实,这就是索引的意义。


8
-1这是错误的。聚集索引的叶级表。
马丁·史密斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.