【问题标题】:Single Autonumber Instead of Multiple Key单个自动编号而不是多个键
【发布时间】:2009-07-01 20:01:40
【问题描述】:

是否有理由对主键使用单个递增字段而不是实际表示唯一记录的多个字段?

我正在开发一个现有的 php 应用程序,并且这些表似乎都有一个“id”键,而不是使用记录实际上唯一的 2 个或更多字段(如用户、拍卖、投标)。

我不是数据库专家,但这对我来说似乎很懒惰(或缺乏经验)。有什么好处(性能或其他)?

更新:我指的不是伪唯一数据(ssn、电子邮件地址等),您可能希望确保数据真正唯一。我说的是具有明显外键引用的表,但不是将这些引用与表本身中的唯一字段一起使用,而是每个表都有一个递增的 ID。

不想引发主观辩论,这对我来说没有意义。

【问题讨论】:

    标签: php sql database database-design


    【解决方案1】:

    使用合成主键有几个优点:

    • 您可以更改关键字段中的值,而无需进行索引更新
    • 索引更小
    • 它使外键关系更简单
    • 由于您不处理字符串,因此永远不会出现编码问题

    数据库通常围绕使用单调递增键构建索引进行特定优化。

    话虽如此,时不时地进行一点非规范化并没有错。如果用例很清楚并且表格相对较小,请做方便的事情。

    【讨论】:

    • -1 "时不时地进行一点非规范化并没有什么问题"
    【解决方案2】:

    这取决于“独特”的定义。是的,姓名、电子邮件地址和 SSN 值应该是“唯一的”。然而,奇怪的事情发生了。在很多情况下,拥有一个单独的 ID 值可以让生活变得更轻松......

    更新

    根据对问题的编辑,我真的认为没有太多需要。听起来你的情况是这样的。一个“连接表”,您只需创建一个表中的 UniqueId 到另一个表的 UniqueId 的关联。

    我认为您正在谈论的一个简单示例是 User -> Role 关联。您必须将用户与角色相关联。一个 UserId 和一个 RoleId。

    您的数据库中的结构类似于

    MappingId (Your Auto Number) (This is the PK)
    UserId (From the user table)
    RoleId (From the Role table)
    

    这个结构对我来说没有意义,我只需要 User 和 RoleId 组成主键,因为这里不需要重复条目。

    如果你有不同的东西可能会改变事情......

    【讨论】:

    • 同意。我通常选择合成主键,然后添加一个具有唯一性约束的索引来识别自然键。这样,如果我在设计期间的初始假设不再成立,我可以更改/删除索引。
    • SSN 将随着时间的推移而被重复使用。毕竟,根据美国人口普查的人口时钟,在美国活着的人数估计为 306,808,431 人……几乎是 SSN 可用空间的 1/3。
    • 更新了问题以使其更清晰,而不是谈论可疑的独特数据。我的意思是一个带有用户 ID、拍卖 ID 等的表,但仍然有一个自动递增的主键。
    • 我希望它更抽象,我猜这可能没什么帮助。示例:“出价”表包含拍卖 ID、用户 ID 和出价金额(以及有关出价的其他数据)。那他们为什么要使用bidid作为主键呢?这不仅仅是连接表,而且在我看来,您可能希望使用其他键来避免重复数据。因此,用户不能多次出价相同的金额(确保代码应该检查这一点,但数据库不应该也确保这一点吗?
    【解决方案3】:

    哦,天哪,看来我们又开始了伟大的自然键与代理键的辩论了。

    最简单的原因是防止数据冗余。自然键往往需要多个键,这些键可能会在数据库的生命周期内发生变化。

    例如,如果一个人结婚并更改了他们的姓氏,那么该姓氏必须在所有被引用的地方更新。

    如果您将外键设置为更新级联,这不是问题,因为数据库会为您完成。

    随着您的表格嵌套越来越多,您可能会发现您的键需要越来越多的列。我实际上已经看到了一个具有七列主键的表。对于只有四列的表。

    【讨论】:

    • 关于冗余,现在代码负责检查重复数据,而不是数据库停止重复数据。例如,在提示此问题的代码中,在提交拍卖报价之前,该代码必须检查数据库中是否存在来自同一用户的同一拍卖的任何相同价值的报价。当然无论如何它都应该这样做,但是如果代码失败,数据库将不会停止它。在那种情况下,会有重复的数据。
    • R. Bemrose 写道: 如果您将外键设置为更新级联,这不是问题,因为数据库会为您完成。但是,在您的数据库之外对该记录的所有引用都将丢失。如果你有与其他系统的接口,你就有麻烦了。
    • @Tim Lytle:没有什么能阻止你拥有独特的约束。
    【解决方案4】:

    您通常希望主键上有一个聚集索引。拥有复合的、聚集的主键的问题在于,当您插入新行时,SQL 必须将新记录粘贴在其他记录之间,这意味着洗牌。此外,主键越大,存储它所需的空间就越多。

    Here 是一篇关于使用 GUID 作为主键的文章,但对于复合键也是如此。

    另见this great answer

    【讨论】:

      【解决方案5】:

      嗯,id 会从 1-infinity 对您的数据库进行顺序排序。用户名等是临时的,并不总是有序的。因此,据推测,它会使搜索更快。另外,您似乎建议让多个键表示一个项目。这通常会减慢速度,因为现在必须检查两件事以确保某件事是正确的,而不是一件。

      【讨论】:

        【解决方案6】:

        这里有几点使用自动编号

        • 自动编号是一个唯一键 建立外键关系 更易于维护和使用

          自动编号是数字,因此使用起来非常简单,不会乱七八糟 他们起来。我的意思是,如果你的 主键是一个字符串,你的 开发人员忘记将其放入 单引号会破坏你的 性能

          使用自动编号是正常的标准做法

          您仍然可以将其他字段设为“唯一”

          使用自动编号更容易重置序列

          如果您需要按顺序向前跳,使用 数字而不是属性的组合,或 字符串

        只是一些事情......

        【讨论】:

          【解决方案7】:

          在大多数情况下,当这些字段真正唯一地标识记录所代表的实体时,这真的不是很清楚。我一次又一次地看到在商业思维中根深蒂固的旧数据库概念阻碍进一步发展的案例。

          【讨论】:

            【解决方案8】:

            我曾经尝试在数据库中使用的几乎所有“自然”键组合最终都随着时间的推移变得不唯一。随着抽象变得泄漏,数据模型需要快速发展。

            这包括姓名、电话号码、SSN、法律文件参考、页码、电子邮件地址、用户名、项目编号以及我在职业生涯中尝试使用的其他一些东西。

            除此之外,关于写入新记录、比较外键等性能的其他答案就足够了。

            您可以保留当前业务逻辑的唯一性,而无需将其放入主键中——只需在自然键列上设置唯一索引即可。与任何索引一样,您需要为插入和更新付出代价,但如果它恰好也是一个有用的索引(有助于覆盖一些查询),那就更好了。

            【讨论】:

            • 因此,如果“自然”键被代理键替换,假设用户名成为用户 ID(唯一生成的数字),为什么不使用用户 ID(以及其他不可变 ID)作为键相关表?
            • 根据定义,PK 是唯一的。出于争论的目的,每次构建唯一约束时,您都刚刚创建了一个 PK。为什么不干脆打破表格并用视图替换它?
            【解决方案9】:

            这一切都取决于您的数据结构有多“正常”。根据定义,高度规范化的数据库只能有一个主键字段。在这种情况下,几乎没有任何理由使用序列号或自动生成的数字作为 PK。数据结构应该设计为具有唯一条目的PK(跟踪人是一个问题,只有这么多名字)。

            当然,规范化会带来性能损失,因此对数据库进行反规范化以使其可用(对于 Web 应用程序非常常见)。对于一个高度去规范化的数据库,很多时候如果不使用表中的每个字段就不可能获得 PK。请记住,对结构进行非规范化的原因是为了提高性能。我熟悉的所有数据库都会为每个 PK 建立一个索引。索引越大,维护索引的开销就越大。

            构建巨大的索引会破坏插入和更新时间的性能,使反规范化无用(除非它是只读数据库)。搜索巨大的索引也需要更长的时间,并且比较小的索引使用更多的内存。

            总的来说,出于性能原因,为需要多个字段以获得唯一 PK 的任何表自动生成 PK 通常是有利的。

            【讨论】:

              【解决方案10】:

              是的,这会引发争论。

              一般来说,主键数据应该是不可变的,而当使用从表数据派生的自然键时,情况往往不是这样。如前所述,诸如 SSN 之类的东西通常可以更改,从而摆脱不变性。

              单调递增的代理键,如“自动编号”或“身份”列,是自然键的简单替代品。但是,它们可能容易出现索引效率低下的问题,因为它们在 B 树样式索引算法中可能无法很好地平衡。这可以通过在 MS SQL Server 中使用随机生成的代理键(如唯一标识符,即 GUID)来解决,但我读到这也会对性能产生影响。

              一般来说,我使用从自动编号或身份等顺序功能生成的代理键,以便于表连接。

              【讨论】:

                猜你喜欢
                • 2021-01-17
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2022-09-23
                • 1970-01-01
                相关资源
                最近更新 更多