一般来说,数据库中的每个表都应该有一个身份字段用作PK吗?

jco*_*lum 43 sql database database-design

即使我问它,这似乎是重复,但我搜索并没有找到它.对于SO来说这似乎是一个很好的问题 - 即使我确信我可以在许多博客上找到它等等.因此,博客上的辩论可能会比您在博客上引起的争论更多.

我遇到了一个连接问题:收回太多记录.我认为这是"扩张".我在连接集中添加了一个表,并且扩展的行数太多了.通常在发生这种情况时,我会添加一个选择连接中涉及的所有ID字段.这样,扩展正在发生的地方非常明显,我可以更改连接的ON来修复它.除了这种情况,我添加的表没有ID字段.对我来说,这是一个问题.但也许我错了.

问题:数据库中的每个表都应该有一个用作PK的IDENTITY字段吗?在每个表中都有ID字段有什么缺点吗?如果你有理由相信这个表永远不会用在PK/FK关系中怎么办?

相关但不重复:拥有标识列不是一个好主意?

显然这场辩论已经持续了一段时间.应该知道.

这篇文章(代理与自然键)也是相关的.

Qua*_*noi 61

有两个概念很接近但不应混淆:IDENTITYPRIMARY KEY

每个表(罕见条件除外)都应该有PRIMARY KEY一个值,即一个唯一标识行的值或一组值.

请参阅此处以了解原因.

IDENTITY是列的属性SQL Server,表示将使用递增值自动填充列.

由于此属性的性质,此列的值本质上是UNIQUE.

但是,不会在列上自动创建UNIQUE约束或UNIQUE索引IDENTITY,并且在发出后SET IDENTITY_INSERT ON可以将重复值插入IDENTITY列中,除非它已被明确UNIQUE约束.

IDENTITY列不一定是a PRIMARY KEY,但通常用于填充代理PRIMARY KEYs

它在任何特定情况下可能有用,也可能没用.

因此,您的问题的答案:

问题:数据库中的每个表都应该有一个用作PK的IDENTITY字段吗?

这是:

没有.有些情况下,数据库表不应该有一个IDENTITY字段作为PRIMARY KEY.

有三个案例出现在我的脑海中,当时最好的想法IDENTITYPRIMARY KEY:

  • 如果你PRIMARY KEY是复合的(就像在多对多链接表中一样)
  • 如果你PRIMARY KEY很自然(比如国家代码)
  • 如果您PRIMARY KEY在数据库中应该是唯一的(在这种情况下,您使用GUID/ UUID/ NEWID)

所有这些情况都意味着以下情况:

IDENTITY当你关心你的值PRIMARY KEY并明确地将它们插入你的表时,你不应该拥有它.

更新:

多对多链接表应该具有id它们作为复合键链接的表的一对.

它是一个自然的复合键,你必须使用(和make UNIQUE),所以没有必要为此生成一个代理键.

我不明白为什么你想many-to-many从任何其他表引用链接表,除了它们链接的表,但我们假设你有这样的需要.

在这种情况下,您只需通过组合键引用链接表.

这个查询:

CREATE TABLE a (id, data)
CREATE TABLE b (id, data)
CREATE TABLE ab (a_id, b_id, PRIMARY KEY (a_id, b_id))
CREATE TABLE business_rule (id, a_id, b_id, FOREIGN KEY (a_id, b_id) REFERENCES ab)

SELECT  *
FROM    business_rule br
JOIN    a
ON      a.id = br.a_id
Run Code Online (Sandbox Code Playgroud)

比这个更有效:

CREATE TABLE a (id, data)
CREATE TABLE b (id, data)
CREATE TABLE ab (id, a_id, b_id, PRIMARY KEY (id), UNIQUE KEY (a_id, b_id))
CREATE TABLE business_rule (id, ab_id, FOREIGN KEY (ab_id) REFERENCES ab)

SELECT  *
FROM    business_rule br
JOIN    a_to_b ab
ON      br.ab_id = ab.id
JOIN    a
ON      a.id = ab.a_id
Run Code Online (Sandbox Code Playgroud)

,原因很明显.

  • @jcollum:更改“主键”的值(而不是布局)是糟糕设计的标志。“主键”的全部要点是它永远不会改变。这是标识行的内容。你的“主键”要么是自然的(这意味着它从本质上来说永远不会改变),要么是替代的(这意味着你永远不想改变它,因为它从一开始就没有意义)。“多对多”链接表是“自然”“主键”的一个示例。它与其他(可能是代理)“主键”一样稳定。 (2认同)

Gre*_*g D 14

几乎总是肯定的.我通常默认包含一个身份字段,除非有令人信服的理由不这样做.我很少遇到这样的原因,身份字段的成本很低,所以一般我都包括.

我唯一想到的就是我不知道的是一个高度专业化的数据库,它被用作数据存储区而不是关系数据库,其中DBMS几乎用于除了重要的关系建模之外的所有功能.(这是一个高容量,高周转率数据缓冲的东西.)

  • 我非常后悔每次尝试快捷方式并避免使用任意主键.我确信我将在我设计的每个数据库中都包含一个非域驱动的主键... (6认同)
  • 如果没有自然密钥,请使用人工密钥(SQL Server用语中的标识)作为pk. (4认同)
  • @Will:我认为这个评论值得一个答案。也许讨论您对非域驱动主键的看法 (2认同)

HLG*_*GEM 12

我坚信自然键通常比人工键差得多,因为你无法控制它们是否会改变,这会导致可怕的数据完整性或性能问题.

但是,有一些(很少)自然键在没有身份字段的情况下是有意义的(想到两个字母的州缩写,这些官方类型的缩写很少变化.)

任何用于建模多对多关系的连接表的表可能也不需要额外的标识字段.将两个关键字段组合在一起主键可以正常工作.

除此之外,我通常会向大多数其他表添加一个标识字段,除非在特定情况下给出令人信服的理由而不是.不能在表上创建主键或者使用代理键无法在可能的其他字段上放置唯一索引(除非您真的喜欢解析重复项),这是一种不好的做法.

  • 阿门!如果有任何可能的变化,切勿使用关键字段. (3认同)
  • 假设*任何*在编程中永远不会改变是一个坏主意. (2认同)