5

虽然我犯了这个罪,但在我看来,没有任何充分的理由让表没有身份字段主键。

优点: - 无论您是否愿意,您现在都可以唯一地识别表中的每一行,这是以前无法做到的 - 如果没有表上的主键,您将无法进行 sql 复制

缺点: - 表的每一行额外的 32 位

例如,考虑需要将用户设置存储在数据库表中的情况。您有一列用于设置名称和一列用于设置值。不需要主键,但是对于您创建的任何表来说,拥有一个整数标识列并将其用作主键似乎是最佳实践。

除了大小之外还有其他原因每个表不应该只有一个整数标识字段吗?

4

11 回答 11

14

当然,单数据库解决方案中的一个示例是,如果您有一个国家表,使用ISO 3166-1-alpha-2 国家代码作为主键可能更有意义,因为这是一个国际标准,并且查询更具可读性(例如CountryCode = 'GB',相对于CountryCode = 28)。类似的论点可以应用于ISO 4217 货币代码

在使用复制的 SQL Server 数据库解决方案中,UNIQUEIDENTIFIER密钥会更有意义,因为某些类型的复制需要 GUID(如果有多个源数据库,也更容易避免密钥冲突!)。

于 2009-03-22T23:18:36.887 回答
10

不需要代理键的表的最明显示例是多对多关系:

CREATE TABLE Authorship (
  author_id INT NOT NULL,
  book_id   INT NOT NULL,
  PRIMARY KEY (author_id, book_id),
  FOREIGN KEY (author_id) REFERENCES Authors (author_id),
  FOREIGN KEY (book_id) REFERENCES Books (book_id)
);

在设计标记系统时,我也更喜欢自然键:

CREATE TABLE Tags (
  tag VARCHAR(20) PRIMARY KEY
);

CREATE TABLE ArticlesTagged (
  article_id INT NOT NULL,
  tag        VARCHAR(20) NOT NULL,
  PRIMARY KEY (article_id, tag),
  FOREIGN KEY (article_id) REFERENCES Articles (article_id),
  FOREIGN KEY (tag) REFERENCES Tags (tag)
);

tag_id这比使用代理“ ”键有一些优势:

  • 您可以确保标签是唯一的,而无需添加多余的UNIQUE约束。
  • 您可以防止两个不同的标签具有完全相同的拼写。
  • 引用标签的从属表已经有标签文本;他们无需加入即可Tags获取文本。
于 2009-03-23T00:17:39.503 回答
7

每个表都应该有一个主键。它是整数、GUID 还是“设置名称”列都没有关系。类型取决于应用程序的要求。理想情况下,如果要将表连接到另一个表,最好使用 GUID 或整数作为主键。

于 2009-03-22T23:16:19.807 回答
4

是的,有充分的理由。您可以拥有语义上有意义的真实密钥,而不是人为的身份密钥。此外,为多对多表设置单独的自动递增主键也不是一个好主意。出于某些原因,您可能希望选择 GUID。

话虽如此,我通常使用自动递增的 64 位整数作为主键。

于 2009-03-22T23:18:56.337 回答
4

每个表都应该有一个主键。但它不需要是单个字段标识符。以财务系统为例,您可能将日记帐表上的主键作为日记帐 ID 和行号。这将为每一行生成唯一的组合(日记帐 ID 将是其自己表中的主键)

您的主键需要定义如何将表链接到其他表。

于 2009-03-22T23:23:18.433 回答
2

我不认为每个表都需要一个主键。有时您只想通过它们的主键“连接”两个表的内容。

所以你有一个表users和一个表groups(每个都有主键),你有第三个表users_groups,只有两个列(用户和组),其中用户和组相互连接。

例如,用户 = 3 和组 = 6 的行会将主键为 3 的用户链接到主键为 6 的组。

于 2009-03-22T23:24:51.440 回答
2

不将主键定义为身份的一个原因是将主键定义为 GUID 或填充有外部生成的值。

一般来说,每一个本身具有语义意义的表都应该有主键,而主键应该没有语义意义。实现多对多关系的连接表本身没有意义,因此它不需要这样的主键(它已经通过它的值有一个)。

于 2009-03-22T23:25:22.437 回答
1

要成为一个正确规范化的表,每一行应该只有一个可识别的键。许多表已经具有自然键,例如唯一的发票号。我同意,尤其是在存储如此便宜的情况下,在所有表上都有一个自动编号/身份键几乎没有开销,但在这种情况下,这是真正的键。

如果用于参考数据,我个人不使用此方法的另一个领域,通常我们有一个描述和一个值

Code, Description
'L', 'Live'
'O', 'Old'
'P', 'Pending'

在这种情况下,将代码设置为主键可确保没有重复,并且更易于阅读。

于 2009-03-22T23:22:16.003 回答
1

自然主键和代理主键之间的关键区别(对不起)是自然键的值包含信息,而代理键的值不包含信息。

为什么这很重要?那么自然主键根据定义保证是唯一的,但它的值通常不能保证保持不变。当它改变时,你必须在多个地方更新它。

代理键的值没有实际意义,只是用于标识该行,因此永远不需要更改。它是模型的一个特征,而不是域本身。

所以我要说代理键不合适的唯一地方是关联表,它只包含引用其他表中行的列(大多数多对多关系)。该表携带的唯一信息是两行(或多行)之间的关联,并且它已经仅由代理键值组成。在这种情况下,我会选择一个复合主键。

如果这样的表具有包语义,或者带有有关关联的附加信息,我将添加一个代理键。

于 2009-12-11T14:12:54.587 回答
0

主键总是一个好主意。它允许非常快速和轻松地加入表格。它帮助可以读取系统表的外部工具进行连接,从而允许不太熟练的人通过拖放创建自己的查询。它还使参照完整性的实现变得轻而易举,这从一开始就是一个好主意。

于 2009-11-13T16:59:09.267 回答
0

我确信为网络巨头工作的一些非常聪明的人会这样做。虽然我不知道为什么他们自己的原因,但我知道 PK-less 表有意义的 2 种情况:

  • 导入数据。该表是临时的。插入和全表扫描需要尽可能快。此外,我们需要接受重复记录。稍后我们将清理数据,但导入过程需要工作。
  • DBMS 中的分析。识别一行没有用——如果我们需要这样做,那不是分析。我们只需要一个看起来像表格的非关系、冗余、可怕的 blob。我们将通过编写适当的 SQL 查询来构建汇总表或物化视图。

Note that these cases have good reasons to be non-relational. But normally your tables should be relational, so... yes, they need a primary key.

于 2015-10-11T11:07:35.957 回答