【问题标题】:Should primary keys be always assigned as clustered index是否应始终将主键分配为聚集索引
【发布时间】:2011-06-03 14:30:44
【问题描述】:

我有一个存储员工详细信息的 SQLServer 表,列 ID 是 GUID 类型,而列 EmployeeNumber 是 INT 类型。大多数时候,我会在进行连接和选择条件时处理 EmployeeNumber。

我的问题是,将 PrimaryKey 分配给 ID 列而 ClusteredIndex 分配给 EmployeeNumber 是否明智?

【问题讨论】:

  • @Lamak:我很确定这是不正确的。一张表只能有一个聚集索引,但不一定要在主键上。
  • @Lamak:不正确。主键和聚集索引键不相关。
  • 是的,没错,我的错。如果该表上没有其他聚集索引,则主键会自动创建聚集索引。
  • @Lamak 你的说法不正确。 SQL Server 数据库中的主键不必是集群的。创建列约束时,您可以指定 PRIMARY KEY NONCLUSTERED,然后将 CLUSTERED 索引应用于另一列。 (msdn.microsoft.com/en-us/library/aa258255(v=SQL.80).aspx)
  • 分公司的数据将与总公司同步,在这种情况下,唯一可靠的 PK 类型被发现是 GUID。从您的所有回答中我可以理解的是,永远不要在 GUID 上使用聚集索引,这绝对使 EmployeeNumber 成为最适合聚集索引的列,而 PK 用于 ID。

标签: sql sql-server clustered-index


【解决方案1】:

在主键以外的其他对象上使用聚集索引将提高 SELECT 查询的性能,这将利用该索引。

但是您会降低 UPDATE 查询的性能,因为在大多数情况下,它们依赖于主键来找到您要更新的特定行。

CREATE 查询也可能会降低性能,因为当您在索引中间添加新行时,必须(物理上)移动很多行。这不会发生在具有增量的主键上,因为新记录将始终添加到最后,并且不会移动任何其他行。

如果您不知道哪种操作最需要性能,我建议将聚集索引保留在主键上,并在常用搜索条件上使用非聚集索引。

【讨论】:

    【解决方案2】:

    理想的聚集索引键是:

    1. 顺序
    2. 选择性(没有重复,每条记录都是唯一的)
    3. 在查询中使用

    一般来说,使用 GUID 作为聚集索引键是一个非常糟糕的主意,因为它会在添加行时导致大量碎片。

    为清晰而编辑:

    PK 和 Clustered key 确实是独立的概念。您的 PK 不需要是您的聚集索引键。

    根据我自己的经验,在实际应用中,与您的 PK 相同的字段应该/将是您的集群密钥,因为它符合上面列出的相同标准。

    【讨论】:

    • 我很确定“...您的 PK 将是您在 SQL Server 中的集群键...”这句话并不完全正确。例如,聚集索引可以基于唯一键。否则,我喜欢你的回答。
    • 如果您需要全局唯一性的好处,您可以使用顺序 GUID (NEWSEQUENTIALID)。
    • 主键不必是集群的。请参阅有关问题的 cmets。
    【解决方案3】:

    由于 EmployeeNumber 是唯一的,我会将其设为 PK。在 SQL Server 中,PK 通常是聚集索引。

    加入 GUID 实在是太可怕了。 @JNK 很好地回答了这个问题。

    【讨论】:

    • 嗯。正如几个 cmets 和对这个问题的帖子所证明的那样,似乎存在一种常见的误解,即主键始终是聚集的,或者是聚集索引的唯一选择。正如我(和 Remus)在别处指出的那样,情况并非如此。
    【解决方案4】:

    是的,可以有一个非聚簇的主键,也可以有一个与主键完全无关的聚簇键。默认情况下,主键也成为聚集索引键,但这不是必需的。

    主键是一个逻辑概念:是数据模型中用于引用实体的键。
    聚集索引键是一个物理概念:是您希望行在磁盘上存储的顺序。

    选择不同的集群键受多种因素的影响,例如键宽度,当您想要一个比主键更窄的集群键时(因为集群键在每个 非聚集索引。或者支持频繁的范围扫描(在时间序列中很常见),当使用date between '20100101' and '20100201' 之类的查询频繁访问数据时(date 上的聚集索引键将是合适)。

    这个话题之前已经在这里讨论过很恶心,另见What column should the clustered index be put on?

    【讨论】:

      【解决方案5】:

      聚集索引使数据按该顺序物理存储。因此,在测试连续行的范围时,聚集索引有很大帮助。

      GUID 是非常糟糕的聚集索引,因为它们的顺序不是一个合理的排序模式。除非输入顺序有帮助(例如最近的招聘),否则 Int Identity 列并没有好多少

      由于您可能不是在寻找员工范围,因此聚集索引可能并不重要,除非您可以分割您通常不感兴趣的员工块(例如终止日期)

      【讨论】:

      • GUIDS 可以成功地用作聚集索引,只要您使用 NEWSEQUENTIALID() 函数生成它们;这有它自己的问题,因为您只能使用一台机器来保证它们是连续的。但我同意你的其他观点,如果可能的话,最好找到一个自然键。
      【解决方案6】:

      首先,我不得不说,我对选择 GUID 作为该表的主键存有疑虑。我认为 EmployeeNumber 可能是一个更好的选择,并且员工自然独特的东西会比这更好,例如雇主必须合法获得的 SSN(或 ATIN)(至少在美国)。

      除此之外,您永远不应该将聚集索引基于 GUID 列。聚集索引指定表中行的物理顺序。由于 GUID 值(理论上)是完全随机的,因此每个新行都将落在随机位置。这对性能非常不利。有一种叫做“顺序”GUID 的东西,但我认为这有点 hack。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-12-21
        • 2012-12-30
        • 1970-01-01
        • 1970-01-01
        • 2010-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多