5

我最近得到了建议,我应该将所有表从使用堆索引转换为每个表都有一个聚集索引。采用这种策略的后果是什么?例如,定期重组数据库更重要吗?数据增长?插入速度很慢的危险?如果 PK 是 GUID,页面碎片整理的危险?我的应用程序的显着速度增加? 你有什么经验?

为了作为获得好的答案的灵感,以下是我从 stackoverflow 上的其他线程中收集到的一些“事实”

  1. 几乎可以肯定要在数据库中的每个表上建立聚集索引。如果一张桌子没有。大多数常见查询的性能更好。
  2. 聚集索引在 GUID 上并不总是坏事……这完全取决于您的应用程序的需求。INSERT 速度会受到影响,但 SELECT 速度会有所提高。
  3. GUID 字段中的聚集索引的问题在于 GUID 是随机的,因此当插入新记录时,必须移动磁盘上的大部分数据才能将记录插入到表的中间。
  4. 在 GUID 有意义并通过将相关数据彼此靠近来提高性能的情况下,GUID 上的聚集索引是可以的http://randommadness.blogspot.com/2008/07/guids-and-clustered-indexes.html
  5. 集群不会影响查找速度 - 一个唯一的非聚集索引应该可以完成这项工作。
4

3 回答 3

9

如果您的键是 GUID,那么它上的非聚集索引可能与它上的聚集索引一样有效。这是因为在 GUID 上,您绝对永远无法对它们进行范围扫描(between 'b4e8e994-c315-49c5-bbc1-f0e1b000ad7c' and '3cd22676-dffe-4152-9aef-54a6a18d32ac'可能意味着什么??)。GUID 聚集索引键的宽度为 16 字节,比您从堆中获得的行 ID 更宽,因此 PK GUID 上的 NC 索引实际上是可以在讨论中进行辩护的策略。

但是使主键成为聚集索引键并不是在堆上构建聚集索引的唯一方法。您是否有其他频繁查询请求某个列的范围?典型的候选者是date,state或之类的列deleted。如果这样做,那么您应该考虑将这些列设置为聚集索引键(它不必唯一的),因为这样做可能有助于查询请求范围,例如“昨天的所有记录”。

堆具有显着性能优势的唯一场景是插入,特别是批量插入。如果您的负载不是很重,那么您绝对应该使用聚集索引。请参阅聚集索引设计指南

回顾你的观点:

几乎可以肯定要在数据库中的每个表上建立聚集索引。如果一张桌子没有。大多数常见查询的性能更好。

可以满足大多数查询的范围要求的聚集索引将显着提高性能,真的。可以满足顺序要求的聚簇索引也很有帮助,但没有一个可以满足范围的索引那么有用。

聚集索引在 GUID 上并不总是坏事……这完全取决于您的应用程序的需求。INSERT 速度会受到影响,但 SELECT 速度会有所提高。

只有探测 SELECT 会得到改进:SELECT ... WHERE key='someguid';。按对象 ID 和外键查找的查询将受益于此聚集索引。NC 索引也可以达到同样的目的。

GUID 字段中的聚集索引的问题在于 GUID 是随机的,因此当插入新记录时,必须移动磁盘上的大部分数据才能将记录插入到表的中间。

错误的。在索引中插入位置不必移动数据。它可能发生的最坏情况是页面拆分。页面拆分(不知何故)很昂贵,但不是世界末日。您的评论建议必须移动所有数据(或至少“重要”部分)以为新行腾出空间,这远非如此。

在 GUID 有意义并通过将相关数据彼此靠近来提高性能的情况下,GUID 上的聚集索引是可以的 http://randommadness.blogspot.com/2008/07/guids-and-clustered-indexes.html

我无法想象 GUID 可以拥有“相关数据”的场景。GUID 是典型的随机结构,两个随机 GUID 如何以任何方式关联?Donald 给出的场景有一个更好的解决方案:Resolving PAGELATCH Contention on High Concurrent INSERT Workloads,实现起来更便宜(需要更少的存储空间)并且也适用于唯一键(链接文章中的解决方案不适用于唯一键,仅适用于外键键)。

集群不会影响查找速度 - 一个唯一的非聚集索引应该可以完成这项工作。

对于探测(查找特定的唯一键)是的。NC 索引几乎与聚集索引一样快(NC 索引查找确实需要额外的键查找来获取其余列)。聚集索引的亮点是范围扫描,因为聚集索引可以覆盖任何查询,而可能满足相同范围的 NC 索引可能会失去覆盖范围并触发Index Tipping Point

于 2010-12-13T21:35:26.957 回答
2

我还建议您阅读 Kimberly Tripp 的The Clustered Index Debate Continues...,其中她非常清楚地详细说明了拥有 *良好的集群键而不是拥有堆的所有好处。

几乎所有操作都更快 -是的!甚至插入和更新!

但这需要一个好的集群密钥,并且具有非常随机和不可预测性质的 GUID 不被认为是集群密钥的良好候选者。作为集群键的 GUID 是不好的——无论它们是否具有应用意义——只是避免这些。

您最好的选择是一个窄、稳定、独特且不断增加的键 - 类型的列INT IDENTITY理想地满足所有这些要求。

有关为什么 GUID 不能成为好的集群键以及它有多糟糕的更多背景信息,请参阅 Kim Tripp 的更多博客文章:

于 2010-12-13T22:04:20.473 回答
1

我可以推荐《SQL Performance Explained》这本书——这是一本关于索引的 200 页的书。

它还提到了聚集索引的性能何时比普通索引差。问题之一是聚集索引本身是 B 树。因此,当您在同一张表上有其他索引时,它们不能指向特定的行 - 相反,它们指向聚集索引中的“键”,因此数据的“路径”变得更长。

于 2012-11-20T21:34:40.627 回答