主键是否应该总是分配为聚集索引?

11
我有一个存储员工详情的SQLServer表格,其中ID列是GUID类型,而EmployeeNumber列是INT类型。在做联接和选择操作时,大多数情况下我会使用EmployeeNumber。
我的问题是,是否明智将PrimaryKey分配给ID列,而将ClusteredIndex分配给EmployeeNumber?

1
@Lamak:我非常确定那不正确。一张表只能有一个聚集索引,但它不一定要在主键上。 - Daniel Pratt
1
@Lamak:不正确。主键和聚集索引键是无关的。 - Remus Rusanu
是的,没错。如果表上没有其他聚集索引,主键会自动创建一个聚集索引。 - Lamak
@Lamak 您的说法不正确。 SQL Server 数据库中的主键不必是聚集的。当您创建列约束时,可以指定 PRIMARY KEY NONCLUSTERED,然后将聚集索引应用于另一列。(http://msdn.microsoft.com/en-us/library/aa258255(v=SQL.80).aspx) - Tony
分支机构的数据将与总部同步,因此唯一可靠的PK类型是GUID。从您所有的回答中我所理解的是,永远不要在GUID上使用聚集索引,这使得EmployeeNumber成为最适合聚集索引的列,而ID则是PK。 - AbrahamJP
只是为了进一步阐明,在SQL Server中,我相信默认情况下主键被用作聚集索引,但正如其他人所提到的,聚集索引可以在非主键列上指定。 - Dr. Wily's Apprentice
6个回答

12

可以使用非聚集主键,并且可以有一个完全不相关的聚集键。默认情况下,主键也会成为聚集索引键,但这不是必须的。

主键是一个逻辑概念:用于引用实体的关键字。
聚集索引键是一个物理概念:用于在磁盘上存储行的顺序。

选择不同的聚集键是由各种因素驱动的,例如关键字宽度,当您希望聚集键比主键窄时(因为聚集键在每个非聚集索引中都被复制)。或者支持频繁的范围扫描(在时间序列中很常见),当数据经常使用查询访问,例如date between '20100101' and '20100201' (在date上的聚集索引键是适当的)。

这个主题已经在这里被反复讨论过,也可以参考What column should the clustered index be put on?


11

理想的聚集索引键应该是:

  1. 连续的
  2. 有选择性(没有重复项,每个记录都是唯一的)
  3. 窄的
  4. 在查询中使用

一般来说,使用 GUID 作为聚集索引键是一个非常糟糕的想法,因为随着行的添加,它会导致大量的分片。

澄清编辑:

主键和聚集键确实是不同的概念。您的主键不需要成为聚集索引键。

实际应用中,根据我的经验,与您的主键相同的字段应该/将成为聚集键,因为它符合上述相同的标准。


3
我相信句子“...your PK will be your clustered key in SQL server...”并不完全正确。例如,聚簇索引可以基于唯一键。除此之外,我认同你的回答。 - Daniel Pratt
2
如果您需要全局唯一性的好处,可以使用顺序GUID(NEWSEQUENTIALID)。 - Cade Roux
主键不一定要聚集。请参考问题中的评论。 - Tony

2
首先,我必须说我对将GUID作为此表的主键选择有所疑虑。我认为EmployeeNumber可能是更好的选择,并且员工自然独特的某些属性会更好,例如SSN(或ATIN),雇主无论如何都必须合法地获得它们(至少在美国)。
抛开这一点,您永远不应该基于GUID列构建聚集索引。聚集索引指定表中行的物理顺序。由于GUID值(理论上)完全随机,每个新行都将落在随机位置。这对性能非常不利。有一种称为“连续”GUID的东西,但我认为这有点像黑客行为。

1

如果在非主键字段上使用聚集索引,将会提高SELECT查询的性能,因为它将利用此索引。

但是,在大多数情况下,UPDATE查询依赖于主键来查找要更新的特定行,因此您将失去性能。

CREATE查询也可能会失去性能,因为当您在索引中间添加新行时,必须移动许多其他行。如果使用自增的主键,则不会发生这种情况,因为新记录始终添加在末尾,不会移动任何其他行。

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


0

聚集索引会导致数据按照特定顺序物理存储。因此,在测试连续行范围时,聚集索引非常有帮助。

GUID是非常糟糕的聚集索引,因为它们的顺序不符合有意义的排序模式。Int Identity列也不太好,除非输入顺序有帮助(例如,最近的雇用)。

由于您可能不会寻找员工范围,因此哪个是聚集索引可能并不重要,除非您可以分段处理经常不感兴趣的员工块(例如,终止日期)。


只要使用NEWSEQUENTIALID()函数生成,GUID可以成功地用作聚集索引;然而这也有自己的问题,因为你只能使用一台机器来保证它们是顺序的。但我同意你的其他观点,如果可能的话最好找到自然键。 - Tony

0

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

使用GUID进行连接非常糟糕。@JNK对此回答得很好。


1
嗯。正如对这个问题的几条评论和帖子所证明的那样,似乎存在一个普遍误解,即主键始终是聚集索引或聚集索引的唯一选择。正如我(和Remus)在其他地方指出的那样,情况并非如此。 - Daniel Pratt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接