SQL Server堆与聚簇索引

Geo*_*ge2 28 sql-server heap clustered-index sql-server-2008

我正在使用SQL Server 2008.我知道如果表没有聚簇索引,那么它被称为堆,否则存储模型称为聚簇索引(B-Tree).

我想了解更多关于堆存储的确切含义,它看起来是什么以及它是否被组织为"堆"数据结构(例如最小堆,最大堆).有推荐的读数吗?我想要更多内部,但不是太深.:-)

乔治,提前谢谢

Qua*_*noi 38

堆存储与这些堆无关.

堆只是意味着记录本身没有被排序(即没有相互链接).

插入记录时,它只会插入数据库找到的空闲空间.

更新基于堆的表中的行不会影响其他记录(尽管它会影响二级索引)

如果在HEAP表上创建辅助索引,则RID(一种指向存储空间的物理指针)将用作行指针.

聚集索引意味着记录是a的一部分B-Tree.插入记录时,B-Tree需要重新链接.

更新聚簇表中的行会导致重新链接B树,即更新其他记录中的内部指针.

如果在聚簇表上创建辅助索引,则聚簇索引键的值将用作行指针.

这意味着聚簇索引应该是唯一的.如果聚簇索引不是唯一的,则会将一个特殊的隐藏列uniquifier附加到索引键上,使其成为唯一(并且大小更大).

还值得注意的是,在列上创建二级索引会使值或聚簇索引的键成为secondayry索引键的一部分.

通过在集群表上创建索引,实际上总是获得一个复合索引

CREATE UNIQUE CLUSTERED INDEX CX_mytable_1234 (col1, col2, col3, col4)

CREATE INDEX IX_mytable_5678 (col5, col6, col7, col8)
Run Code Online (Sandbox Code Playgroud)

索引IX_mytable_5678实际上是以下列的索引:

col5
col6
col7
col8
col1
col2
col3
col4
Run Code Online (Sandbox Code Playgroud)

这还有一个副作用:

DESC在群集表中的单个列索引条件有意义在SQL Server

这个指数:

CREATE INDEX IX_mytable ON mytable (col1)
Run Code Online (Sandbox Code Playgroud)

可以在这样的查询中使用:

SELECT  TOP 100 *
FROM    mytable
ORDER BY
       col1, id
Run Code Online (Sandbox Code Playgroud)

,而这一个:

CREATE INDEX IX_mytable ON mytable (col1 DESC)
Run Code Online (Sandbox Code Playgroud)

可以在这样的查询中使用:

SELECT  TOP 100 *
FROM    mytable
ORDER BY
       col1, id DESC
Run Code Online (Sandbox Code Playgroud)

  • 如果后者没有发生页面拆分,那么插入到堆中的速度比"B-Tree"快一点*,如果发生页面拆分,则**快*更快(即没有地方可以进入新行)并且数据应该在叶子之间重新分配). (2认同)
  • 根据我的理解,非聚集索引也不是索引聚簇密钥,而是二级索引*中的叶节点包含*聚簇密钥.就像nonclustered在整个聚簇键中有一个隐含的`INCLUDE`子句.这就是为什么使用小型群集密钥对性能很重要的原因.如果您有一个大的聚簇键,非聚簇索引的叶节点要大得多,因此加载索引页需要更多的I/O. (2认同)

mar*_*c_s 11

堆只是没有聚类键的表 - 没有强制执行某个物理订单的键.

我不建议在任何时候使用堆 - 除非您临时使用表来批量加载外部文件,然后将这些行分发到其他表.

在其他所有情况下,我强烈建议使用群集密钥.默认情况下,SQL Server将使用主键作为群集键 - 在大多数情况下,这是一个不错的选择.除非您使用GUID(UNIQUEIDENTIFIER)作为主键,在这种情况下使用它作为您的群集键是一个可怕的想法.

请参阅Kimberly Tripp的优秀博客文章GUIDs作为主要和/或群集密钥聚集索引辩论继续为优秀的解释,为什么你应该总是有一个群集密钥,以及为什么GUID是一个可怕的群集密钥.

我的建议是:

  • 在99%的情况下,尝试使用a INT IDENTITY作为主键,让SQL Server也将其作为集群密钥
  • 例外#1:如果您批量加载大量数据,那么在没有临时表的主/集群密钥的情况下,您可能没问题
  • 异常#2:如果必须使用GUID作为主键,则将聚类键设置为不同的列 - 最好是INT IDENTITY- 如果没有其他列可以使用,我甚至会为此目的创建一个单独的INT列