即使我问它,这似乎是重复的,但我搜索并没有找到它。对于SO来说这似乎是一个很好的问题 - 即使我确信我可以在许多博客上找到它等等。因此,博客上的辩论可能会比您在博客上引起的争论更多。
我遇到了一个连接问题:收回太多记录。我认为这是“扩张”。我在连接集中添加了一个表,并且扩展的行数太多了。通常在发生这种情况时,我会添加一个选择连接中涉及的所有ID字段。这样,扩展正在发生的地方非常明显,我可以更改连接的ON来修复它。除了这种情况,我添加的表没有ID字段。对我来说,这是一个问题。但也许我错了。
问题:数据库中的每个表都应该有一个用作PK的IDENTITY字段吗?在每个表中都有ID字段有什么缺点吗?如果你有理由相信这个表永远不会用在PK / FK关系中怎么办?
相关但不重复:When having an identity column is not a good idea?
显然这场辩论是going on for a while。应该知道。
This post(代理与自然键)也是相关的。
答案 0 :(得分:60)
有两个概念很接近,但不应混淆:IDENTITY
和PRIMARY KEY
每个表(稀有条件除外)都应该有PRIMARY KEY
,这是一个唯一标识行的值或一组值。
请参阅here了解原因。
IDENTITY
是SQL Server
中列的属性,这意味着该列将使用递增值自动填充。
由于此属性的性质,此列的值本身就是UNIQUE
。
但是,UNIQUE
列上不会自动创建UNIQUE
约束或IDENTITY
索引,并且在发出SET IDENTITY_INSERT ON
后,可以将重复值插入IDENTITY
}列,除非明确UNIQUE
约束。
IDENTITY
列不一定是PRIMARY KEY
,但通常用于填充代理PRIMARY KEY
在任何特定情况下,它可能有用,也可能没用。
因此,你问题的答案是:
问题:数据库中的每个表都应该有一个用作PK的IDENTITY字段吗?
就是这样:
IDENTITY
字段设为PRIMARY KEY
。如果将IDENTITY
作为PRIMARY KEY
并不是最好的主意,我会想到三个案例:
PRIMARY KEY
是复合的(如多对多链接表中那样)PRIMARY KEY
是自然的(例如,州代码)PRIMARY KEY
在数据库中应该是唯一的(在这种情况下,您使用GUID
/ UUID
/ NEWID
)所有这些案件都意味着以下条件:
IDENTITY
的值并明确将其插入表格时,您不应该PRIMARY KEY
。<强>更新强>
多对多链接表应该将id
对作为复合键链接到的表。
这是一个你必须使用的自然复合键(并使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
比这个效率更高:
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
,原因很明显。
答案 1 :(得分:14)
几乎总是如此。我通常默认包含一个身份字段,除非有令人信服的理由不这样做。我很少遇到这样的原因,身份字段的成本很低,所以通常我都包括。
我唯一想到的就是我不知道的是一个高度专业化的数据库,它被用作数据存储区而不是关系数据库,其中DBMS几乎用于除了重要关系之外的所有功能造型。 (这是一个高容量,高周转率数据缓冲的东西。)
答案 2 :(得分:11)
我坚信自然键通常远比人工键差,因为你无法控制它们是否会改变,这会导致可怕的数据完整性或性能问题。
然而,有些(很少)自然键在没有身份字段的情况下是有意义的(想到两个字母的州名缩写,这些官方类型缩写很少变化。)
任何用于建模多对多关系的连接表的表可能也不需要额外的标识字段。将两个关键字段组合在一起主键可以正常工作。
除此之外,我通常会向大多数其他表添加一个标识字段,除非在特定情况下给出令人信服的理由而不是。不能在表上创建主键或者如果您使用代理键无法在可能的其他字段上放置唯一索引(尽管您真的喜欢解析重复项),这是一种不好的做法。
答案 3 :(得分:4)
每个表都应该有一组唯一标识它的字段。是否存在与数据字段分开的数字标识符字段取决于您尝试建模的域。并非所有数据都容易属于“单一数字ID”范例,因此强制它是不合适的。鉴于此,许多数据很容易适应这种范例,因此需要这样的标识符。在任何编程环境中总是做X都没有一个答案,这是另一个例子。
答案 4 :(得分:4)
没有。每当你有一个带有人工身份列的表时,你还需要识别表的自然主键,并确保对这组列也有唯一约束,这样你就不会得到两行相同的行。从无意义的身份栏中偶然发现。
添加标识列不是免费的。向表中添加不必要的标识列会产生开销 - 对于标识值,每行存储通常为4个字节,加上一个额外的索引(可能在每行8-12个字节加上开销)。计算出最具成本效益的查询计划也需要一点点,因为每个表都有一个额外的索引。当然,如果桌子很小而机器很大,这个开销并不重要 - 但对于最大的系统来说,这很重要。
答案 5 :(得分:3)
如果您已经建模,设计,规范化等,那么您将没有标识列。
您将识别表格的自然和候选键。
由于物理架构(例如,窄,数字,严格单调增加),您可以决定代理键,因为使用nvarchar(100)列不是一个好主意(仍需要唯一约束)。
或者因为意识形态:它们吸引了我找到的OO开发者。
好的,假设ID列。随着你的数据库变得越来越复杂,比如说几层,你怎么能直接使用parent和grand-.child表。你不能:你总是需要中间表和索引良好的PK-FL列。使用复合键,它就在你身边......
不要误会我的意思:我用它们。但我知道为什么我会用它们......
编辑:
我有兴趣一方面整理“永远ID”+“无存储过程”匹配,另一方面用“使用存储过程”+“当受益时ID”另一方面......
答案 6 :(得分:1)
我想不出在每个表中都有ID字段的任何缺点。提供您的ID字段类型可为您的桌面增长提供足够的空间。
但是,您不一定需要单个字段来确保行的标识。 所以不,单个ID字段不是强制性的。
主要和外国键不仅可以包含一个字段,还可以包含多个字段。这对于实现N-N关系的表来说是典型的。
您可以在桌面上完美地拥有PRIMARY KEY (fa, fb)
:
CREATE TABLE t(fa INT , fb INT);
ALTER TABLE t ADD PRIMARY KEY(fa , fb);
答案 7 :(得分:1)
是的,绝大多数情况。
边缘情况或异常可能是这样的:
但除此之外,我认为没有充分理由反对使用主键来唯一标识表中的每一行,在我看来,使用IDENTITY字段是最佳选择之一(我更喜欢代理键自然键 - 它们更可靠,更稳定,永不改变等。)。
马克
答案 8 :(得分:1)
识别Identity字段和密钥之间的区别......每个表都应该有一个密钥,以消除无意中输入代表同一“实体”的多个行的数据损坏。如果表中唯一的键是无意义的代理键,则实际上缺少此函数。
otoh,没有表'需要'一个标识,当然不是每个表都受益于一个...示例是:一个包含短和功能键的表,一个没有任何其他表通过外部引用它的表密钥或与另一个表处于一对一或零关系的表...这些都不需要标识
答案 9 :(得分:0)
我会说,如果你能在你的表中找到一个简单,自然的键(即一列),那就用它作为键而不是标识列。
我通常会为每个表提供某种唯一标识符,无论是自然的还是生成的,因为我保证每一行都以某种方式唯一标识。
就个人而言,我避免像瘟疫这样的IDENTITY(增加标识列,如1,2,3,4)列。它们会造成很多麻烦,特别是如果您从该表中删除行。如果表中没有自然键,我会使用生成的uniqueidentifiers。
无论如何,不知道这是否是公认的做法,对我来说似乎是对的。 YMMV。