SQL Server 堆与聚集索引
Posted
技术标签:
【中文标题】SQL Server 堆与聚集索引【英文标题】:SQL Server heap v.s. clustered index 【发布时间】:2010-11-23 09:45:12 【问题描述】:我使用的是SQL Server 2008。我知道如果一个表没有聚集索引,那么它就称为堆,否则存储模型称为聚集索引(B-Tree)。
我想了解更多关于堆存储的确切含义、它的外观以及它是否被组织为“堆”数据结构(例如最小堆、最大堆)的更多信息。有什么推荐的读物吗?我想要更多的内部知识,但不要太深。 :-)
提前致谢, 乔治
【问题讨论】:
【参考方案1】:Books Online 是最好的来源!
整个Database Engine - Planning and Architecture - Tables and Index Data Structures Architecture 很好的内部介绍。
From this link您可以下载在线图书的本地副本(免费)。它是对所有 Sql 2008 问题的最佳(和官方)参考。
【讨论】:
【参考方案2】:堆存储与these heaps无关。
堆只是意味着记录本身没有排序(即不相互链接)。
当您插入一条记录时,它只是被插入到数据库找到的可用空间中。
更新基于堆的表中的行不会影响其他记录(尽管会影响二级索引)
如果您在HEAP
表上创建二级索引,则RID
(一种指向存储空间的物理指针)用作行指针。
聚集索引意味着记录是B-Tree
的一部分。插入记录时,B-Tree
需要重新链接。
更新聚簇表中的一行会导致 B 树的重新链接,即。 e.更新其他记录中的内部指针。
如果在聚簇表上创建二级索引,则聚簇索引键的值用作行指针。
这意味着聚集索引应该是唯一的。如果聚集索引不是唯一的,则会将一个名为 uniquifier
的特殊隐藏列附加到唯一的索引键(并且大小更大)。
还值得注意的是,在列上创建二级索引会使值或聚集索引的键成为二级索引键的一部分。
通过在聚簇表上创建索引,实际上你总是得到一个复合索引
CREATE UNIQUE CLUSTERED INDEX CX_mytable_1234 (col1, col2, col3, col4)
CREATE INDEX IX_mytable_5678 (col5, col6, col7, col8)
索引IX_mytable_5678
实际上是对以下列的索引:
col5
col6
col7
col8
col1
col2
col3
col4
这还有一个副作用:
聚集表上单列索引中的DESC
条件在SQL Server
中是有意义的
这个索引:
CREATE INDEX IX_mytable ON mytable (col1)
可以在这样的查询中使用:
SELECT TOP 100 *
FROM mytable
ORDER BY
col1, id
,而这个:
CREATE INDEX IX_mytable ON mytable (col1 DESC)
可以在这样的查询中使用:
SELECT TOP 100 *
FROM mytable
ORDER BY
col1, id DESC
【讨论】:
那么,向堆中插入一行是否更快/更慢/与向 B-Tree 中插入一行相同? 如果B-Tree
没有发生页面拆分,则插入堆有点快,并且快得多如果发生分页(即没有地方进入新行,数据应该在叶子之间重新分配)。
该死的你很好,Quassnoi...你知道网络上有多少关于聚集索引的垃圾...
据我了解,并不是非聚集索引也索引聚集键,而是二级索引中的叶节点包含聚集键。这就像非集群有一个隐含的 INCLUDE
子句和整个集群键。这就是为什么拥有一个小的集群键对性能很重要的原因。如果你有一个大的聚集键,非聚集索引的叶子节点要大得多,所以加载索引页需要更多的 I/O。
@PaulWilliams:这仅适用于唯一的非聚集索引。如果非聚集索引不是唯一的,它也会在分支页面中包含聚集键(以及唯一标识符,如果它被使用)。【参考方案3】:
堆只是没有集群键的表 - 没有强制特定物理顺序的键。
我真的不建议在任何时候使用堆 - 除非您临时使用表来批量加载外部文件,然后将这些行分发到其他表。
在所有其他情况下,我强烈建议使用集群键。默认情况下,SQL Server 将使用主键作为集群键——在大多数情况下,这是一个不错的选择。除非您使用 GUID (UNIQUEIDENTIFIER) 作为主键,在这种情况下使用它作为您的集群键是一个可怕的想法。
请参阅 Kimberly Tripp 的优秀博文 GUIDs as Primary and/or the clustering key 和 The Clustered Index Debate Continues,了解为什么您应该始终拥有一个集群键,以及为什么 GUID 是一个可怕的集群键。
我的建议是:
在 99% 的情况下,尝试使用INT IDENTITY
作为主键,并让 SQL Server 也将其设为集群键
例外 #1:如果您要批量加载大量数据,则可能没有临时表的主键/集群键
异常 #2:如果您必须使用 GUID 作为主键,则将您的集群键设置为不同的列 - 最好是 INT IDENTITY
- 我什至会为此目的创建一个单独的 INT 列,如果没有可以使用其他列
马克
【讨论】:
以上是关于SQL Server 堆与聚集索引的主要内容,如果未能解决你的问题,请参考以下文章