虽然我犯了这个罪,但在我看来,没有任何充分的理由让表没有身份字段主键。
优点: - 无论您是否愿意,您现在都可以唯一地识别表中的每一行,这是以前无法做到的 - 如果没有表上的主键,您将无法进行 sql 复制
缺点: - 表的每一行额外的 32 位
例如,考虑需要将用户设置存储在数据库表中的情况。您有一列用于设置名称和一列用于设置值。不需要主键,但是对于您创建的任何表来说,拥有一个整数标识列并将其用作主键似乎是最佳实践。
除了大小之外还有其他原因每个表不应该只有一个整数标识字段吗?
虽然我犯了这个罪,但在我看来,没有任何充分的理由让表没有身份字段主键。
优点: - 无论您是否愿意,您现在都可以唯一地识别表中的每一行,这是以前无法做到的 - 如果没有表上的主键,您将无法进行 sql 复制
缺点: - 表的每一行额外的 32 位
例如,考虑需要将用户设置存储在数据库表中的情况。您有一列用于设置名称和一列用于设置值。不需要主键,但是对于您创建的任何表来说,拥有一个整数标识列并将其用作主键似乎是最佳实践。
除了大小之外还有其他原因每个表不应该只有一个整数标识字段吗?
当然,单数据库解决方案中的一个示例是,如果您有一个国家表,使用ISO 3166-1-alpha-2 国家代码作为主键可能更有意义,因为这是一个国际标准,并且查询更具可读性(例如CountryCode = 'GB'
,相对于CountryCode = 28
)。类似的论点可以应用于ISO 4217 货币代码。
在使用复制的 SQL Server 数据库解决方案中,UNIQUEIDENTIFIER
密钥会更有意义,因为某些类型的复制需要 GUID(如果有多个源数据库,也更容易避免密钥冲突!)。
不需要代理键的表的最明显示例是多对多关系:
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
获取文本。每个表都应该有一个主键。它是整数、GUID 还是“设置名称”列都没有关系。类型取决于应用程序的要求。理想情况下,如果要将表连接到另一个表,最好使用 GUID 或整数作为主键。
是的,有充分的理由。您可以拥有语义上有意义的真实密钥,而不是人为的身份密钥。此外,为多对多表设置单独的自动递增主键也不是一个好主意。出于某些原因,您可能希望选择 GUID。
话虽如此,我通常使用自动递增的 64 位整数作为主键。
每个表都应该有一个主键。但它不需要是单个字段标识符。以财务系统为例,您可能将日记帐表上的主键作为日记帐 ID 和行号。这将为每一行生成唯一的组合(日记帐 ID 将是其自己表中的主键)
您的主键需要定义如何将表链接到其他表。
我不认为每个表都需要一个主键。有时您只想通过它们的主键“连接”两个表的内容。
所以你有一个表users
和一个表groups
(每个都有主键),你有第三个表users_groups
,只有两个列(用户和组),其中用户和组相互连接。
例如,用户 = 3 和组 = 6 的行会将主键为 3 的用户链接到主键为 6 的组。
不将主键定义为身份的一个原因是将主键定义为 GUID 或填充有外部生成的值。
一般来说,每一个本身具有语义意义的表都应该有主键,而主键应该没有语义意义。实现多对多关系的连接表本身没有意义,因此它不需要这样的主键(它已经通过它的值有一个)。
要成为一个正确规范化的表,每一行应该只有一个可识别的键。许多表已经具有自然键,例如唯一的发票号。我同意,尤其是在存储如此便宜的情况下,在所有表上都有一个自动编号/身份键几乎没有开销,但在这种情况下,这是真正的键。
如果用于参考数据,我个人不使用此方法的另一个领域,通常我们有一个描述和一个值
Code, Description
'L', 'Live'
'O', 'Old'
'P', 'Pending'
在这种情况下,将代码设置为主键可确保没有重复,并且更易于阅读。
自然主键和代理主键之间的关键区别(对不起)是自然键的值包含信息,而代理键的值不包含信息。
为什么这很重要?那么自然主键根据定义保证是唯一的,但它的值通常不能保证保持不变。当它改变时,你必须在多个地方更新它。
代理键的值没有实际意义,只是用于标识该行,因此永远不需要更改。它是模型的一个特征,而不是域本身。
所以我要说代理键不合适的唯一地方是关联表,它只包含引用其他表中行的列(大多数多对多关系)。该表携带的唯一信息是两行(或多行)之间的关联,并且它已经仅由代理键值组成。在这种情况下,我会选择一个复合主键。
如果这样的表具有包语义,或者带有有关关联的附加信息,我将添加一个代理键。
主键总是一个好主意。它允许非常快速和轻松地加入表格。它帮助可以读取系统表的外部工具进行连接,从而允许不太熟练的人通过拖放创建自己的查询。它还使参照完整性的实现变得轻而易举,这从一开始就是一个好主意。
我确信为网络巨头工作的一些非常聪明的人会这样做。虽然我不知道为什么他们自己的原因,但我知道 PK-less 表有意义的 2 种情况:
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.