主键应该是不变的吗?


26

一个关于计算器最近的问题引起了有关主键的不变性讨论。我以为主键应该是不变的,这是一种规则。如果有一天某天可能会更新主键,我认为您应该使用代理键。但是,它不在SQL标准中,某些RDBMS的“级联更新”功能允许更改主键。

所以我的问题是:拥有可能会更改的主键是否仍然是一种不好的做法?拥有可变主键有何弊端?

Answers:


25

仅当主键链接到外键或用作数据库外部的标识符(例如,指向该项目的页面的URL中)时,才需要主键是不可变的。

另一方面,如果它包含一些可能会更改的信息,则仅需要具有可变密钥。如果记录没有可以用作键的简单,不变的标识符,则我总是使用代理键。


7
为什么你“ 需要的主键,如果它连接到一个外键是不可改变的”?如OP所述,大多数RDBMS具有“级联”更新功能。
塔纳托斯州

1
@Thanatos大多数(实际上是我所遇到的)rdbms都不允许可变的主键,但具有级联更新。在公认的dba知识中,主键不应包含任何信息,而应仅是唯一的记录标识符(因此,甚至不包括时间戳,从其推迟的记录范围,等等)。
jwenting 2011年

5
@jwenting:我们在谈论同一件事吗?“大多数rdbms不允许可变的主键”包括什么?MySQL和PostgreSQL都允许可变的主键,并允许级联更新……正如我认为标准SQL所说的那样。还有,“一般公认的dba智慧”?我遇到了许多反对代理密钥的DBA,以及许多反对自然密钥的DBA。
Thanatos

2
@Thanatos支持“所有表都必须有替代表”的论据缺乏书目参考,他们引用了“通常接受的dba智慧”,但从未引用过书。规范书籍说,如果:A.不存在自然键,B.多列键超出3列,或者C.您将一直在更改键。因此:当自然适合时,自然替代;当自然适合时,代孕。
TulainsCórdova13年

4
@ user61852:什么?
Guffa 2013年

15

主键应由确定唯一性所需的任何元组组成。数据是否可以更改无关紧要。仅记录的唯一性很重要。那就是数据库的概念设计。

当我们进入实现领域时,最安全的事情就是使用代理键。


15

是的,我认为主键应该是不变的。

即使有明显的候选键,我也总是使用代理键。在少数情况下我还没有做到这一点,我几乎总是后悔。而且,无论您认为密钥是多么不可变,您都无法防范数据输入错误-告诉用户他们不能编辑那部分信息,因为它是主密钥,这不会让人感到难过。


关于数据输入错误的要点
Tim Goodman 2010年

richeym,似乎您正在说明为什么键不能是不变的:用户可能想要更改它们。
nvogel

4
@dportas-我的观点是,我喜欢PK是不可变的,因此即使我认为可以从表数据(例如,电子邮件,用户名)派生一个明显的密钥,也请始终使用代理密钥。
richeym 2010年

2

如果主键发生更改,数据库和用户之间的缓存机制将失去效力。


2

为什么不?因为要消除一列?

仅仅因为需求要求三列是唯一的,并不意味着它必须是主键。您可能会认为该规则将永远持续下去(还记得那次会议上,当负责人的部门经理发誓永远不会改变吗?您知道,刚刚被解雇的那个。),但是不会。

我实现的每个级联更新都不会得到报酬,如果我自己编写代码,也不会获得奖金。

计算机不需要密钥的任何含义;恕我直言,密钥用于计算机,让人们搞乱其余数据。


1
“密钥用于计算机,让人们搞乱其余数据。” +1,很好。

2

拥有一个其值可能会改变的键是很不错的做法。

好的密钥的属性包括稳定性。不变性是理想的,但不是前提条件。为实现不变性而引入人工密钥是不明智的做法。

国际标准书号(ISBN)为例。它非常稳定,但并非一成不变:有时候,图书出版商会犯错误,而且-恐怖!-可能出现重复的ISBN号。这是否意味着ISBN不应该被接受为计算机数据库中的候选密钥?当然不是。ISBN的优点之一是它拥有可信赖的来源,可以为全球所有用户解决问题。

好的密钥ISBN还有其他一些方面,那就是缺乏无意义的自动递增整数密钥,例如,熟悉度(书本行业的每个人都知道或熟悉ISBN),可验证的(ISBN印刷在所有现代书籍上),可以参照DBMS进行验证(ISBN是固定宽度,包括校验和),等等。


3
ISBN是固定宽度,除非不是固定宽度(请参阅ISBN-10与ISBN-13)。
的CVn

那么,您将如何建议处理重复的ISBN?在我所知道的所有RDBMS中,您必须在字段上具有UNIQUE约束才能使用它作为主键。
通配符

1

一切可能不变的事物都应该如此。它有助于确保正确性,并在您希望使应用程序成为多线程时有所帮助。


1

是的,主键必须是不变的,并且必须是非空且唯一的。但是,我还没有找到一个可以实现主键不变性的数据库,因此,如果您确实愿意的话,您可能可以继续修改它们的值。


0

正如一些评论已经说过的那样,一种解决方案是使用新的主键

例如(以@onedaywhen为例),假设存在存在书籍列表的表格Books,并且我们“用来”将ISBN确定为主键。但是,有些作者犯了键入错误的ISBN的错误,因此,他们要求更改ISBN,这涉及以下任务:

  • 在表Books中创建一个新注册表
  • 将所有参考从旧ISBN指向新ISBN。(*)
  • 最后,从表Books中删除旧注册表。

(*)可能很难找到使用外键的数据库模型的所有引用,但某些模型却缺少它。

Table Books
ISBN  is the primary key
NAME is a simple field.
etc.

我们将其更改为

Table Books
InternalBookId as the primary key
ISBN as a simple field or an indexed field.
NAME is a simple field.
etc.

新的InternalBookId甚至可以是自动数字值。

缺点:

  • 它添加了一个使用更多空间/资源的新字段。

  • 它可能需要重写整个模型。

  • 新模型可能不那么自我解释。

  • 允许更改“主键”。
  • 甚至允许删除或重构“主键”,例如,将“图书”更改为ISBN-13非常简单,只需删除较旧的列并创建一个新列即可

新表:

Table Books
InternalBookId as the primary key
ISBN13 is a new field.
NAME is a simple field.
etc.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.