一般来说,数据库中的每个表都应该有一个标识字段用作PK?
这似乎是一个重复,即使我问,但我搜查,没有find它。 这似乎是一个很好的问题 – 尽pipe我确信我可以在很多博客上find它。 SO会有比你在博客上更多的辩论。
我遇到了一个连接问题:收回太多的logging。 我认为这是“扩张”。 我添加了一个表的连接集和行数扩展,太多了。 通常,当发生这种情况时,我会添加一个所有参与连接的ID字段的select。 这种方式很明显,扩展发生的地方,我可以改变连接的ON来解决它。 除了在这种情况下,我添加的表没有ID字段。 对我来说,这是一个问题。 但也许我错了。
问题:数据库中的每个表是否应该有一个用作PK的IDENTITY字段? 每个表中都有一个ID字段有什么缺点? 如果你确信这张桌子永远不会用在PK / FK关系中呢?
相关,但不重复: 当有一个标识列不是一个好主意?
显然这个辩论已经持续了一段时间 。 应该是已知的。
这篇文章 (代理与自然键)也是相关的。
有两个概念是密切的,但不应该混淆: IDENTITY
和PRIMARY KEY
每个表格(除了极less数条件外)都应该有一个PRIMARY KEY
,即一个值或一组唯一标识一行的值。
请参阅这里讨论为什么。
IDENTITY
是SQL Server
中列的属性,这意味着该列将被自动填充并增加值。
由于这个属性的性质,这个列的值本质上是UNIQUE
。
但是,在IDENTITY
列上不会自动创buildUNIQUE
约束或UNIQUE
索引,并且在发出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
)
所有这些情况都意味着以下情况:
当你关心PRIMARY KEY
的值时,你不应该有IDENTITY
,并且明确地将它们插入到你的表中。
更新:
多对多链接表应该有一对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
,原因很明显。
几乎总是是的。 除非有令人信服的理由,否则我通常会默认包含身份字段。 我很less遇到这样的原因,身份领域的成本是最小的,所以一般我都包括在内。
唯一可以想到的是,我不是一个高度专业化的数据库,而是被用作数据存储的数据库,而不是关系数据库,其中除了重要的关系build模之外,几乎所有的function都使用DBMS。 (这是一个高容量,高成交量数据缓冲区的东西。)
我坚信自然密钥往往比人造密钥差得多,因为你经常无法控制它们是否会改变,这会导致可怕的数据完整性或性能问题。
然而,有一些(非常less的)自然钥匙是有意义的,而不是身份领域(两个字母的状态缩写出现在脑海中,这些官方types的缩写极less改变)。
任何一个连接表来模拟一个多对多的关系,也许不需要额外的标识字段。 将两个关键字段组合在一起的主键将工作得很好。
除此之外,一般情况下,我会在大多数其他表格中添加一个标识字段,除非在特定情况下给出一个令人信服的理由。 如果不能在表上创build主键,或者如果使用代理键无法在其他字段上放置唯一索引(以确保唯一性,除非您真的喜欢parsing重复项),否则这是一种糟糕的做法。
每个表都应该有一些唯一标识的字段。 是否存在与数据字段分开的数字标识符字段将取决于您尝试build模的域。 并不是所有的数据都很容易落入“单一的数字身份”范例,因此不适合强制执行。 鉴于此,很多数据很容易适应这种范式,因此需要这样的标识符。 在任何编程环境中总是没有人会回答X,这也是另外一个例子。
不需要。每当有一个具有人工标识列的表时,还需要标识该表的自然主键,并确保该列集上存在唯一的约束,以便不会获得两行与无意义身份栏无意相同。
添加标识列不是免费的。 在表中添加一个不必要的标识列会有一些额外的开销,通常每行存储4个字节的标识值,加上一个额外的索引(可能每行8-12字节加上开销)。 制定出最具成本效益的查询计划也需要一些时间,因为每个表格都有一个额外的索引。 诚然,如果桌子很小,机器很大,这个开销并不重要,但是对于最大的系统来说,这很重要。
如果你有build模,devise,规范化等,那么你将没有身份列。
您将为您的表格标识自然键和候选键。
因为使用nvarchar(100)列不是一个好主意(仍然需要唯一的约束),所以您可以决定使用替代关键字,因为物理结构(如窄,数字,严格单调递增)。
或者是因为意识形态:他们对我find的OO开发者有吸引力。
好的,假设ID列。 当你的数据库变得越来越复杂的时候,说几层,你怎么能直接jon父表和grand-.child表。 你不能:你总是需要中间表和良好的索引PK-FL列。 有了复合钥匙,它就在你身边
不要误解我的意思,我使用它们。 但是我知道我为什么要用它们
编辑:
我有兴趣整理“总是ID”+“没有存储过程”匹配,一方面与“使用存储过程”+“ID时,他们受益”在另一方面…
是的,绝大多数情况下。
边缘情况或例外可能是这样的事情:
- 双向连接表来模拟m:n关系
- 用于批量插入大量数据的临时表
但除此之外,我认为有没有一个很好的理由反对有一个主键来唯一标识表中的每一行,在我看来,使用IDENTITY字段是最好的select之一(我更喜欢代理键比自然键 – 他们更可靠,稳定,永不改变等)。
渣子
识别身份字段和密钥之间的区别…每个表都应该有一个密钥,以消除无意中input代表相同“实体”的多行的数据损坏。 如果一个表唯一的键是一个毫无意义的代理键,那么这个function是有效的丢失。
otoh,没有表'需要'的一个身份,当然不是每个表都有一个好处…例子是:一个简短的function键,没有任何其他表通过外键引用它的表,或一个与另一个表是一对一或零关系的表…这些都不需要一个标识
我会说,如果你可以在你的表(即一列)中find一个简单的自然键,那么用它作为一个键而不是一个标识列。
我通常给每一个表格一些独特的标识符,无论是自然的还是生成的,因为那么我保证每一行都是以某种方式唯一标识的。
就个人而言,我避免了像鼠疫这样的IDENTITY(增加身份列,比如1,2,3,4)列。 他们造成很多麻烦,特别是如果你从表中删除行。 如果表中没有自然键,则使用生成的uniqueidentifiers。
无论如何,不知道这是否是公认的做法,对我来说似乎是正确的。 因人而异。
我想不出在每个表中有一个ID字段的缺点。 提供您的ID字段的types为您的桌子增长提供了足够的空间。
但是,您不一定需要单个字段来确保行的标识。 所以不,一个ID字段不是强制性的 。
主键和外键不但可以由一个字段组成,也可以由多个字段组成 。 这对于实施NN关系的表格是典型的。
你可以完美地在你的桌子上有PRIMARY KEY (fa, fb)
:
CREATE TABLE t(fa INT , fb INT); ALTER TABLE t ADD PRIMARY KEY(fa , fb);