主键与唯一约束?

时间:2008-10-01 16:10:16

标签: database database-design

我目前正在设计一个全新的数据库。在学校里,我们总是学会在每张桌子上放一把主键。

我阅读了很多文章/讨论/新闻组帖子,说最好使用唯一约束(也就是某些数据库的唯一索引)而不是PK。

你的观点是什么?

16 个答案:

答案 0 :(得分:46)

主键实际上只是一个不允许NULL的candidate key。因此,在SQL术语中 - 它与任何其他唯一键没有区别。

然而,对于我们的非理论RDBMS,你应该有一个主键 - 我从来没有听过它的论点。如果该主键是surrogate key,则 还应该natural key(s)上有唯一约束。

要离开的重要一点是,你应该对所有候选人(无论是自然的还是代理的)密钥有唯一的限制。然后,您应该选择Foreign Key中最容易引用的那个作为您的主键*。

您还应该有clustered index *。这个可能是你的主键,或者是一个自然键 - 但它不是必须的。您应该根据表的查询用法选择聚簇索引。如有疑问,主键不是首选。

  • 虽然技术上只需要在外键关系中引用唯一键,但极大地支持主键是公认的标准做法。事实上,如果某些RDBMS只允许主键引用,我不会感到惊讶。

  • 编辑:有人指出Oracle的术语“聚簇表”和“聚簇索引”与Sql Server不同。相当于我在Oracle-ese中所说的是Index Ordered Table,建议用于OLTP表 - 我认为这是SO问题的主要焦点。我假设如果您负责大型OLAP数据仓库,那么您应该对数据库设计和优化有自己的看法。

答案 1 :(得分:38)

您能提供这些文章的参考吗?

我认为没有理由改变尝试过的方法。毕竟,主键是关系数据库的基本设计功能。

使用UNIQUE来达到同样的目的听起来真的很惹我生气。他们的理由是什么?

编辑:我的注意力刚刚回到这个旧答案。也许你所读到的关于PK与UNIQUE的讨论涉及人们制造某种PK的唯一目的是为了强制执行它的唯一性。对此的答案是,如果它是一个键,那么将其设为键,否则使其独一无二。

答案 2 :(得分:10)

主键只是一个特殊处理(自动创建索引等)的候选键(唯一约束)。

我希望那些反对他们的人认为没有理由以不同的方式对待一个密钥。这就是我的立场。

[编辑]显然,即使我自己的答案没有50分,我也无法发表评论。

@chris:我认为没有任何伤害。 “主键”实际上只是语法糖。我一直都在使用它们,但我当然不认为它们是必需的。需要一个唯一的密钥,是的,但不一定是主键。

答案 3 :(得分:9)

非常罕见的非规范化会让你想拥有一张没有主键的表。主键仅根据PK的性质自动具有唯一约束。

如果要保证ADDITION列中主键的唯一性,将使用唯一约束。

总是有PK的规则是好的。

http://msdn.microsoft.com/en-us/library/ms191166.aspx

答案 4 :(得分:5)

您应始终拥有主键。

但是我怀疑你的问题只是措辞有点误导,而你实际上是要问主键是否应该始终是自动生成的数字(也称为代理键),或者某些唯一字段是实际有意义的数据(也是被称为自然键,如人的SSN,书籍的ISBN等。

这个问题是DB领域的一场古老的宗教战争。

我的看法是,如果自然键确实是唯一且永不改变,那么自然键是更可取的。但是,你应该小心,即使看起来像SSN可能会在某些情况下改变SSN的东西。

答案 5 :(得分:3)

在您将从此表与将引用此值的其他表建立关系的情况下,应使用主键。但是,根据表的性质和您考虑应用唯一约束的数据,您可以将该特定字段用作自然主键,而不必建立代理键。当然,代理与自然键是另一个完整的讨论。 :)

如果此表与其他表之间没有建立关系,则可以使用唯一键。例如,一个表包含有效电子邮件地址的列表,在插入新用户记录之前将对其进行比较。或者,如果表中的值具有主键但也必须绝对唯一,则可以使用唯一键。例如,如果您有一个具有用户名的用户表。您不希望将用户名用作主键,但它也必须是唯一的才能将其用于登录目的。

答案 6 :(得分:3)

除非该表是在您处理数据时暂存数据的临时表,否则您总是希望在表上放置主键,这就是原因:

1 - 唯一约束可以允许空值,但主键从不允许空值。如果在具有空值的列上运行具有连接的查询,则从结果数据集中消除这些行,因为null不等于null。这就是大公司甚至可以犯会计错误并重新获利的方式。他们的查询没有显示应该包含在总数中的某些行,因为在其唯一索引的某些列中存在空值。应该使用主键。

2 - 主键上会自动放置一个唯一索引,因此您无需创建一个索引。

3 - 大多数数据库引擎会自动在主键上放置聚簇索引,从而使查询更快,因为行是连续存储在数据块中的。 (这可以更改为将聚簇索引放在不同的索引上,如果这样可以加快查询速度。)如果表没有聚簇索引,则行将不会连续存储在数据块中,从而产生查询因为读/写磁头必须遍历整个磁盘才能获取数据。

4 - 许多前端开发环境需要主键才能更新表或进行删除。

答案 7 :(得分:2)

我们需要在逻辑结构和物理结构之间做出区分,并在理论和实践之间进行类似的区分。

首先:从理论角度来看,如果您没有主键,则表示没有表格。就是这么简单。所以,你的问题不是你的表是否应该有一个主键(当然它应该),而是你如何在你的RDBMS中标记它。

在物理层面,大多数RDBMS将主键约束实现为唯一索引。如果您选择的RDBMS就是其中之一,那么在将列指定为主键并简单地在列上添加唯一约束之间可能没有太大的实际区别。但是:其中一个选项可以捕获您的意图,而另一个选项则不会。所以,这个决定是明智的。

此外,如果主键被正确标记,一些RDBMS可以提供​​额外的功能,例如图表和半自动外键约束支持。

任何告诉你使用唯一约束而不是主键作为一般规则的人应该提供一个非常好的理由。

答案 8 :(得分:1)

关键是主键可以是一个或多个唯一标识表的单个记录的列,其中唯一约束只是对字段的约束,该字段仅允许任何给定数据元素的单个实例。表。

个人而言,我使用GUID或自动递增BIGINTS(SQL SERVER的Identity Insert)用于在我的表中进行交叉引用的唯一键。然后我将使用其他数据来允许用户选择特定记录。

例如,我将有一个员工列表,并且我在幕后使用的每条记录都附有GUID,但是当用户选择员工时,他们会根据以下字段选择它们: LastName + FirstName + EmployeeNumber。

此方案中的主键是LastName + FirstName + EmployeeNumber,而唯一键是关联的GUID。

答案 9 :(得分:1)

  

帖子说最好使用唯一约束(也就是某个db的唯一索引)而不是PK

我想这里唯一的一点是旧的讨论“自然与代理键”,因为唯一索引和pk是相同的。

翻译:

帖子说最好使用自然键而不是代理键

答案 10 :(得分:1)

我通常使用PK和UNIQUE KEY。因为即使您没有在模式中表示PK,也总是在内部为您生成PK。对于SQL Server 2005和MySQL 5都是如此。

但我不在我的SQL中使用PK列。它用于管理目的,例如删除一些错误的行,如果将PK值设置为AUTO INCREMENT,则找出PK值之间的间隙。而且,将PK作为数字而不是一组列或char数组是有意义的。

答案 11 :(得分:1)

我已经写了很多关于这个主题的文章:如果你读过我的任何内容,请注意我可能特指Jet a.k.a. MS Access。

在Jet中,使用非维护的聚簇索引(在紧凑状态下聚集)在PRIMARY KEY上对表进行物理排序。如果表没有PK但是在NOT NULL列上使用UNIQUE约束定义了候选键,那么引擎将为聚簇索引选择一个(如果你的表没有聚簇索引,那么它被称为堆,可能根本就不是表!)引擎如何选择候选键?它可以选择一个包含可空列的列吗?我真的不知道。关键是在Jet中,为引擎指定聚集索引的唯一明确方法是使用PRIMARY KEY。当然,Jet中的PK还有其他用途,例如如果在SQL DDL中从FOREIGN KEY声明中省略了一个键,它将被用作键,但为什么不明确它。

Jet的问题在于,创建表的大多数人都不知道或不关心聚簇索引。事实上,大多数用户(我打赌)在每个表上放置一个自动增量自动编号列,并仅在此列上定义PRIMARY KEY,同时未对自然键和候选键设置任何唯一约束(自动增量列是否实际上可视为没有将它暴露给最终用户的密钥本身就是另一个讨论。我不会在这里详细介绍聚簇索引,但足以说IMO唯一的自动增量列很少是理想的选择。

无论您使用哪种SQL引擎,PRIMARY KEY的选择都是任意的,特定于引擎。通常,引擎会对PK应用特殊含义,因此您应该了解它是什么并将其用于您的优势。我鼓励人们使用NOT NULL UNIQUE约束,希望他们能更好地考虑所有候选键,特别是当他们选择使用“自动编号”列时(应该)在数据模型中没有意义。但我宁愿民间选择一个考虑周全的关键并使用PRIMARY KEY而不是习惯性地将它放在自动增量柱上。

所有桌子都应该有PK吗?我说是的,因为否则意味着你至少错过了引擎提供PK的一点点优势,最糟糕的是你没有数据完整性。

BTW Chris OC在这里提出了一个关于时态表的重点,它需要有序的主键(小写),这些主键不能通过简单的PRIMARY KEY约束(大写的SQL关键字)来实现。

答案 12 :(得分:1)

PRIMARY KEY

<强> 1。空       它不允许Null值。因此,我们引用PRIMARY KEY =       独特的钥匙+不是空的约束。  的 2。 INDEX       默认情况下,它会添加聚簇索引。  第3。 LIMIT       一个表只能有一个PRIMARY KEY列[s]。

独特的钥匙

<强> 1。空       允许空值。但只有一个Null值。  的 2。 INDEX       默认情况下,它会添加UNIQUE非聚集索引。  第3。 LIMIT       一个表可以有多个UNIQUE Key Column [s]。

答案 13 :(得分:0)

如果您打算使用LINQ-to-SQL,如果您计划执行更新,那么您的表将需要主键,如果您计划在断开连接的环境中工作,则需要timestamp列(例如通过WCF服务应用程序传递对象。)

如果你喜欢.NET,PK和FK是你的朋友。

答案 14 :(得分:0)

我提出你可能需要两者。主键本质上需要是唯一的而不是可空的。它们通常是代理键,因为整数创建比字符文件更快的连接,尤其是多字段字符连接。但是,由于这些通常是自动生成的,因此它们不保证数据记录的唯一性,不包括id本身。如果您的表具有唯一的自然键,则应在其上具有唯一索引以防止重复项的数据输入。这是基本的数据完整性要求。

编辑添加:现实世界数据通常没有真正保证规范化表结构中唯一性的自然键也是一个真正的问题,特别是如果数据库是以人为中心的话。姓名,甚至姓名,地址和电话号码相结合(想想父亲和儿子在同一医疗实践中)不一定是唯一的。

答案 15 :(得分:0)

我正在考虑这个问题。如果你使用独特的,你会伤害2. NF。根据这一点,每个非pk属性必须依赖于PK。此唯一约束中的这对属性将被视为PK的一部分。

很抱歉7年后回复此事,但不想开始新的讨论。