使用多列主键有哪些优缺点?

Cur*_*che 15 sql primary-key composite-primary-key

我想看一个例子:

  • 如果这是合适的
  • 当这不合适时

是否有时候数据库的选择会对上述例子产生影响?

Aar*_*ght 34

这似乎是关于代理键的问题,代理键总是自动递增数字或GUID,因此是单个列,而不是自然键,它们通常需要多条信息才能真正独一无二.如果你能够拥有一个只有一列的自然键,那么这一点显然没有实际意义.

有些人会坚持只使用其中一种.花足够的时间使用生产数据库,您将了解到没有与上下文无关的最佳实践.

其中一些答案使用SQL Server术语,但这些概念通常适用于所有DBMS产品:


使用单列代理键的原因:

  • 聚集索引. 当数据库只能附加到聚簇索引时,聚簇索引始终表现最佳 - 否则,数据库必须执行页面拆分.请注意,这仅适用于密钥是顺序的,即自动递增序列或顺序GUID.任意GUID可能会更糟糕的表现.

  • 关系.如果你的关键是3,4,5列长,包括性格类型和其他非压缩数据,你会浪费巨大的空间量,然后,如果你要建立外键关系在其他20桌此键降低性能.

  • 唯一性.有时候,你并不拥有真实自然的关键.也许你的表是某种日志,你可以同时获得两个相同的事件.或者,您的真实密钥类似于物化路径,只能在已插入行之后确定.无论哪种方式,您总是希望您的聚簇索引和/或主键是唯一的,因此如果您没有其他真正独特的信息,您别无选择,只能使用代理键.

  • 兼容性. 大多数人永远不必处理这个问题,但如果自然键包含类似a的东西hierarchyid,那么有些系统甚至可能无法读取它.在这种情况下,您还必须创建一个简单的自动生成的代理键供这些应用程序使用.即使您在自然键中没有任何"怪异"数据,一些DB库在处理多列主键时也会遇到很多麻烦,尽管这个问题很快就会消失.

使用多列自然键的原因

  • 存储.许多使用数据库的人从不使用足够大的数据库来处理这个因素.但是当一个表有数十亿或数万亿行时,您将希望保留此表中可能的绝对最小数据量.

  • 复制.是的,您可以使用GUID或顺序GUID.但GUID有自己的权衡取舍,如果由于某种原因你不能或不想使用GUID,那么多列自然键是复制场景的更好选择,因为它本质上全球唯一的 -是的,你不需要一个特殊的算法来使它独特,它的定义是独一无二.这使得分布式体系结构的推理变得非常容易.

  • 插入/更新性能.代理键不是免费的.如果您有一组唯一经常查询的列,则需要在这些列上创建覆盖索引; 索引最终几乎与表一样大,这会浪费空间,并且每次进行任何修改时都需要更新第二个索引.如果您有可能在表上只有一个索引(聚簇索引),那么您应该这样做!


这就是刚刚想到的东西.如果我突然想起别的什么,我会更新.


Mar*_*ers 5

你几乎总是想要一个主键,所以我假设选择是选择现有的两列作为主键,或者创建一个新的自动递增 PK 并在两列上放置一个普通的唯一约束。

当你想要一个 2 列的主键时:

  • 如果您有一个引用两个其他表的中间表,并且它只包含两个外键,即多对多关系,那么添加额外的列只是为了作为主键是没有意义的。使用您已有的两列作为主键。

当你想要一个自动递增的主键时:

  • 如果您从另一个表引用一个表,您希望目标表的主键较小,因为该数据将作为引用表中的外键重复。您还希望它能够快速进行比较。
  • 您添加到表中的每个索引都包含一个集群键的副本(通常与主键相同)。如果您的集群键比它需要的大,那么该表上的每个索引也将比它需要的大。


Kal*_*see 5

我认为将主键设为自动生成的键并在多列上创建 UNIQUE 约束和索引几乎总是更好(至少从应用程序开发人员的角度来看)。

  • 使用单个自动生成的主键,您将能够轻松地从其他表中添加对此表的引用。
  • 自动生成的主键可以更简单地与 ORM 库配合使用。
  • 此外,如果您的唯一性约束将来发生变化,您不必更改现有的主键。

我遇到了几种令人头疼的情况,因为 DBA 认为多列主键总是足够的,而未来的需求变化证明这是不正确的。