【问题标题】:Primary Key versus Unique Constraint?主键与唯一约束?
【发布时间】:2008-10-01 16:10:15
【问题描述】:

我目前正在设计一个全新的数据库。在学校里,我们总是学会在每个表中放置一个主键。

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

你的观点是什么?

【问题讨论】:

  • 在约束方面,PK表示UNIQUE NOT NULL。

标签: database database-design


【解决方案1】:

主键实际上只是一个不允许 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 数据仓库,您应该已经对数据库设计和优化有自己的看法。

【讨论】:

  • Oracle 不会推荐对每个表都使用聚集索引。
  • 对不起 - 我是一个 MSSQL 人,所以我对 Oracle 的看法并不多。我的理解是,Oracle 聚簇表和索引与 SQL Server 聚簇索引无关。 Oracle 等效项是索引有序表,建议至少用于 OLTP 表。
【解决方案2】:

您能否提供这些文章的参考资料?

我认为没有理由改变久经考验的方法。毕竟,主键是关系数据库的基本设计特征。

使用 UNIQUE 来实现相同的目的对我来说听起来真的很骇人听闻。他们的理由是什么?

编辑:我的注意力刚刚回到这个旧答案。也许您阅读的关于 PK 与 UNIQUE 的讨论涉及人们将某些东西作为 PK 来实现其唯一性的唯一目的。答案是,如果它是键,则将其设为键,否则将其设为 UNIQUE。

【讨论】:

  • 你说如果是key就做key,如果是唯一的就做唯一。但实际上,是什么让钥匙成为钥匙而不是唯一的?你对 key 的定义是什么?
  • @Pacerier 假设我们有一个学生信息数据库。在此数据库中,学生使用主键 StudentNumber 进行标识。在学生表中,我们保留了诸如 SSN/SIN 或其他区域等效项之类的内容。作为键控错误检查的一部分,我们希望该字段是唯一的。但这不是一个关键领域。 (虽然它可能是,假设 StuID 和 SSN 之间的 1:1 对应关系)房间分配也可以是唯一的,但不是关键。 (虽然我更倾向于将学生分配到一个房间而不是一个房间给一个学生)
  • 在您的示例中,为什么不将 SSN/SIN 作为密钥?
  • 学生 ID 写在每份作业上,以及大学与学生之间的每一封信件上。您真的希望您的 SSN 如此漫不经心地乱扔吗?在一个完美的世界里,你是对的。一个通用的个人 ID,可用于任何事情。在现实世界中,机构将自己的数字分配为人员标识符,并将其他候选密钥存档。
  • 你没有解决这个问题......为什么不让学生证成为主键?你是说学生证要改变
【解决方案3】:

主键只是一个候选键(唯一约束),被挑选出来进行特殊处理(自动创建索引等)。

我希望反对他们的人认为没有理由将一把钥匙与另一把钥匙区别对待。这就是我的立场。

[编辑] 显然,如果没有 50 分,我什至无法评论自己的答案。

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

【讨论】:

  • 感谢您的论证。但是有什么害处呢?是否有理由颠覆范式?
  • > 自动创建索引等 并非所有数据库都会自动为 PK 创建索引。例如,Oracle 可以只使用现有索引。
【解决方案4】:

非常罕见的非规范化会让你想要一个没有主键的表。主键作为 PK 的性质自动具有唯一约束。

当您希望在主键的添加中保证列的唯一性时,将使用唯一约束。

永远有PK是个好规则。

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

【讨论】:

    【解决方案5】:

    您应该始终拥有一个主键。

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

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

    我的看法是,如果自然键确实是唯一的并且永不改变,则它们更可取。但是,您应该小心,即使是像个人 SSN 这样看似稳定的东西,在某些情况下也可能会发生变化。

    【讨论】:

    • 同意,例如,随着数据输入错误得到修复以及人们因身份盗用等原因获得新的,SSN 会经常更改。
    • 我的问题不是你的意思。它实际上是使用主键与唯一键约束。
    • 好的。那么答案是:你应该总是有一个主键。我认为建议您的人可能会感到困惑,请注意,PK 也始终是唯一的键-
    • 我实际上是来寻找这个答案的?
    【解决方案6】:

    除非表是临时表,以便在您处理数据时暂存数据,否则您总是希望在表上放置一个主键,原因如下:

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

    2 - 唯一索引将自动放置在主键上,因此您不必创建一个。

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

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

    【讨论】:

    • 第 4 点 +1。在极少数情况下,您可能希望创建没有 PK 的表,我遇到的所有 GUI 行编辑工具都将停止工作。
    【解决方案7】:

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

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

    【讨论】:

    • 使用一些数据库,您可以在唯一索引的字段上创建外键
    【解决方案8】:

    我们需要在这里区分逻辑构造和物理构造,同样也需要区分理论和实践。

    首先:从理论上讲,如果您没有主键,那么您就没有表。就是这么简单。因此,您的问题不是您的表是否应该有主键(当然应该),而是您如何在 RDBMS 中标记它。

    在物理级别,大多数 RDBMS 将主键约束实现为唯一索引。如果您选择的 RDBMS 是其中之一,那么在将列指定为主键和简单地对列设置唯一约束之间可能没有太大的实际区别。但是:其中一个选项会捕获您的意图,而另一个则不会。所以,这个决定是不费吹灰之力的。

    此外,如果正确标记了主键,某些 RDBMS 会提供其他功能,例如图表和半自动外键约束支持。

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

    【讨论】:

      【解决方案9】:

      问题是主键可以是一个或多个列,它们唯一标识表的单个记录,其中唯一约束只是对字段的约束,它只允许在一个给定数据元素的单个实例桌子。

      就我个人而言,我使用 GUID 或自动递增的 BIGIINTS(SQL SERVER 的身份插入)作为用于在我的表之间进行交叉引用的唯一键。然后我将使用其他数据来允许用户选择特定的记录。

      例如,我将有一个员工列表,并为我在幕后使用的每条记录附加一个 GUID,但是当用户选择员工时,他们会根据以下字段选择他们:姓氏 + 名字 + 员工编号。

      在这种情况下,我的主键是 LastName + FirstName + EmployeeNumber,而唯一键是关联的 GUID。

      【讨论】:

      • 我也是这样做的:使用“私人”ID(通常是 BIGINT)作为主键。出于规范化目的,我在源代码或触发器中实现规则。我坚信数据库应该捕获所有数据,并且数据的操作在其他地方完成。
      【解决方案10】:

      帖子说最好使用唯一约束(也就是某些数据库的唯一索引)而不是 PK

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

      翻译:

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

      【讨论】:

        【解决方案11】:

        我通常同时使用 PK 和 UNIQUE KEY。因为即使您没有在架构中表示 PK,也会在内部为您生成一个。 SQL Server 2005 和 MySQL 5 都是如此。

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

        【讨论】:

          【解决方案12】:

          我已经写了很多关于这个主题的文章:如果您阅读了我的任何内容,请清楚我可能专门指的是 Jet a.k.a. MS Access。

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

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

          无论您使用什么 SQL 引擎,PRIMARY KEY 的选择都是任意的并且是特定于引擎的。通常,引擎会对 PK 赋予特殊含义,因此您应该找出它是什么并利用它来发挥自己的优势。我鼓励人们使用 NOT NULL UNIQUE 约束,希望他们能够更多地考虑所有候选键,特别是当他们选择使用(应该)在数据模型中没有意义的“自动编号”列时。但我宁愿人们选择一个经过深思熟虑的键并使用 PRIMARY KEY,而不是出于习惯将其放在自动增量列上。

          所有表都应该有PK吗?我说是的,因为否则至少意味着您错过了引擎提供 PK 的轻微优势,最坏的情况是您没有数据完整性。

          顺便说一句,Chris OC 在这里对临时表提出了一个很好的观点,它需要顺序的主键(小写),而不能通过简单的 PRIMARY KEY 约束(大写的 SQL 关键字)来实现。

          【讨论】:

            【解决方案13】:

            主键

            1.空 它不允许 Null 值。因此,我们参考 PRIMARY KEY = 唯一键 + 非空约束。 2。索引 默认情况下,它会添加一个聚集索引。 3。限制 一张表只能有一个 PRIMARY KEY Column[s]。

            唯一键

            1.空 允许空值。但只有一个 Null 值。 2。索引 默认情况下,它添加一个唯一的非聚集索引。 3。限制 一张表可以有多个 UNIQUE Key Column[s]。

            【讨论】:

            • 请发布您的答案,因为提供链接不是一个合适的选项
            • 感谢您的建议。相应地编辑回复:)
            【解决方案14】:

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

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

            【讨论】:

              【解决方案15】:

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

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

              【讨论】:

                【解决方案16】:

                我自己也在考虑这个问题。如果你使用unique,你会伤害到2.NF。根据这一点,每个非 pk 属性都必须取决于 PK。此唯一约束中的一对属性将被视为 PK 的一部分。

                很抱歉 7 年后才回复这个问题,但不想开始新的讨论。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-05-28
                  • 2020-10-25
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多