聚集索引应该放在什么列?

Xai*_*oft 10 sql sql-server indexing database-design

最近,我一直在阅读所有类型的索引,主要的建议是将聚簇索引放在表的主键上,但如果主键实际上没有在查询中使用(通过选择或连接)并且仅仅用于纯粹的关系目的,因此在这种情况下不会被查询.例如,说我有一个car_parts表,它包含3列,car_part_id,car_part_no,和car_part_title. car_part_id是唯一的主键标识列.在这种情况下car_part_no也是独一无二的,也是最有可能的car_part_title. car_part_no是最受查询的,所以将聚簇索引放在该列而不是car_part_id?问题的基础是什么列实际上应该具有聚集索引,因为您只允许其中一个?

Rem*_*anu 9

当且仅当索引中最左侧的键被过滤时,查询优化器才能使用聚簇或非聚类索引.因此,如果在列(A,B,C)上定义索引,则on B=@b,on C=@c或on上的WHERE条件B=@b AND C=@c将不会完全利用索引(请参阅注释).这也适用于加入条件.任何地方过滤器,包括A将考虑指数:A=@aA=@a AND B=@bA=@a AND C=@cA=@a AND B=@b AND C=@c.

因此,在您的示例中,如果将clustred索引part_no作为最左侧的键,则查找特定的查询part_id使用索引,并且必须存在单独的非聚集索引part-id.

现在关于许多索引中哪一个应该是聚簇索引的问题.如果您有几个具有相同重要性和频率的查询模式,并且在所需密钥的条款上相互矛盾(例如,通过任一 part_no或频繁查询part_id),那么您可以考虑其他因素:

  • width:聚簇索引键用作所有其他非聚簇索引的查找键.因此,如果您选择一个宽键(比如两个uniquidentifier列),那么您将使所有其他索引更宽,从而消耗更多空间,生成更多IO并减慢所有内容.所以,从一个读取点equaly良好的键之间,选择最窄的聚集,使更广泛的人非集群.
  • 争用:如果您有特定的插入和删除模式,请尝试将它们物理分离,以便它们出现在聚集索引的不同部分.例如.如果表充当一个队列,其中所有插入位于一个逻辑端,所有删除位于另一个逻辑端,请尝试布置聚簇索引,以使物理顺序与此逻辑顺序匹配(例如,排队顺序).
  • 分区:如果表非常大并且您计划部署分区,则分区键必须是聚簇索引.典型示例是使用滑动窗口分区方案存档的历史数据.即使实体具有像'entity_id'这样的逻辑主键,clustred索引也由日期时间列完成,该列也用于分区功能.
  • 稳定性:经常更改的密钥是群集密钥的不良候选者,因为每个更新聚簇密钥值并强制所有非聚集索引更新它们存储的查找密钥.作为群集密钥的更新也将有可能重新定位创成不同的页面可引起聚集索引碎片.

注意:没有完全利用,因为有时引擎会选择非聚集索引来扫描而不是聚簇索引,因为它更窄,因此扫描的页面更少.在我的示例中,如果您在(A,B,C)和WHERE过滤器B=@b和查询项目上C有索引,则索引可能会被使用但不会作为搜索,因为扫描仍然比完整群集更快扫描(更少的页面).


mar*_*c_s 5

Kimberly Tripp 始终是索引洞察力的最佳来源之一。

请参阅她的博客文章“不断增加的集群键 - 集群索引辩论 - 再次! ”,其中她非常清楚地列出并解释了一个好的集群键的主要要求 - 它必须是:

  • 独特的
  • 狭窄的
  • 静止的

最重要的是,如果您可以管理:

  • 不断增加

考虑到所有这些,在绝大多数情况下INT IDENTITY(或者BIGINT IDENTITY如果你真的需要超过 20 亿行)是最好的选择。

许多人没有意识到(因此在做出选择时没有考虑到)的一件事是聚集键(构成聚集索引的所有列)将添加到每个索引中表上每个非聚集索引的条目 - 因此“窄”要求变得尤为重要!

此外,由于聚集键用于书签查找(当在非聚集索引中找到一行时查找实际数据行),“唯一”要求也变得非常重要。事实上非常重要,如果您选择(一组)列(一组),该列不保证是唯一的,SQL Server 将为每一行添加一个 4 字节的唯一标识符 --> 从而使您的每一个聚集索引键超宽;绝对不是一件好事。

马克