一尘不染

什么时候应该将主键声明为非聚集的?

sql

在为我之前提出的另一个问题创建测试数据库时,我记得可以声明主键NONCLUSTERED

什么时候使用NONCLUSTERED主键而不是CLUSTERED主键?


阅读 82

收藏
2022-10-21

共1个答案

一尘不染

问题不是“PK 何时应该是 NC”,而是您应该问“聚集索引的正确键是什么”?

答案实际上取决于您如何查询数据。聚集索引比所有其他索引都有一个优势:因为它总是包含所有列,所以总是覆盖。因此,可以利用聚集索引的查询当然不需要使用查找来满足某些预计列和/或谓词。

另一个难题是如何使用索引?典型的模式有以下三种:

  • 探测,当在索引中搜索单个键值时
  • 范围扫描,当检索到一系列键值时
  • 按要求排序,当索引可以满足不需停止排序的排序时

因此,如果您分析您的预期负载(查询)并发现大量查询将使用特定索引,因为它们使用从索引中受益的特定访问模式,那么建议将该索引作为聚集索引是有意义的。

另一个因素是聚集索引键是所有非聚集索引使用的查找键,因此宽聚集索引键会产生连锁反应并扩大所有非聚集索引,而宽索引意味着更多页面、更多 I/O ,更多的记忆,更少的善良。

一个好的聚集索引是稳定的,它在实体的生命周期内不会改变,因为聚集索引键值的变化意味着该行必须被删除并重新插入。

并且一个好的聚簇索引不是随机增长的(每个新插入的键值都大于前一个值)以避免页面拆分和碎片(不弄乱FILLFACTORs)。

那么现在我们知道什么是好的聚集索引键,主键(它是一个数据建模逻辑属性)是否符合要求?如果是,那么 PK 应该是集群的。如果不是,那么 PK 应该是非集群的。

举个例子,考虑一个销售事实表。每个条目都有一个作为主键的 ID。但是绝大多数查询都需要一个日期和另一个日期之间的数据,因此最好的聚集索引键是销售日期,而不是ID。另一个具有与主键不同的聚集索引的示例是选择性非常低的键,例如“类别”或“状态”,只有很少的不同值的键。将具有这种低选择性键的聚集索引键作为最左边的键,例如(state, id),通常是有意义的,因为范围扫描会查找特定“状态”中的所有条目。

关于堆上可能存在非聚集主键的最后一点说明(即根本没有聚集索引)。这可能是一个有效的场景,典型的原因是大容量插入性能至关重要,因为与聚集索引相比,堆的大容量插入吞吐量要好得多。

2022-10-21