【问题标题】:Are there any good reasons to have a database table without an integer primary key?有一个没有整数主键的数据库表有什么好的理由吗?
【发布时间】:2009-03-22 23:12:37
【问题描述】:

虽然我犯了这个罪,但在我看来,没有任何充分的理由让表没有身份字段主键。

优点: - 无论您是否愿意,您现在都可以唯一地识别表格中的每一行,这在以前是无法做到的 - 你不能在你的表上没有主键的情况下进行 sql 复制

缺点: - 表格的每一行额外增加 32 位

以您需要将用户设置存储在数据库表中的情况为例。您有一列用于设置名称和一列用于设置值。不需要主键,但拥有一个整数标识列并将其用作主键似乎是您创建的任何表的最佳实践。

除了大小之外还有其他原因导致每个表不应该只有一个整数标识字段吗?

【问题讨论】:

    标签: database primary-key


    【解决方案1】:

    当然,单数据库解决方案中的一个示例是,如果您有一个国家/地区表,使用 ISO 3166-1-alpha-2 country code 作为主键可能更有意义,因为这是国际标准,并且使查询更具可读性(例如 CountryCode = 'GB' 而不是 CountryCode = 28)。类似的论点可以应用于ISO 4217 currency codes

    在使用复制的 SQL Server 数据库解决方案中,UNIQUEIDENTIFIER 键会更有意义,因为某些类型的复制需要 GUID(如果有多个源数据库,也可以更轻松地避免键冲突!)。

    【讨论】:

    • 你是对的,这是一个很好的理由。对我来说,在这种情况下,我仍然会使用自动递增的 PK 并对国家代码进行唯一约束。此外,您可以使用非 PK GUID 进行复制。只是补充一些想法。 :)
    • @Bobby - 我们最初在 Country 表上使用 INT PK,但它比使用国家代码更痛苦,因此被重构了。是的,你是对的,ROWGUIDCOL 不一定是 PK,但恕我直言,这样做通常是有意义的。
    • 我很敬畏即将宣布您应该始终使用 PK,但我喜欢您的反例。这些基本上是永远不会被修改的外部标识符,因此作为它们自己的 PK 是有效的。
    • 我个人认为查询的可读性不是一个特别好的理由。虽然 ISO 标准代码可能是您所了解的一个很好的例子,但一个国家的 ISO 代码发生变化的可能性仍然大于代理键发生变化的可能性。
    【解决方案2】:

    不需要代理键的表的最明显示例是多对多关系:

    CREATE TABLE Authorship (
      author_id INT NOT NULL,
      book_id   INT NOT NULL,
      PRIMARY KEY (author_id, book_id),
      FOREIGN KEY (author_id) REFERENCES Authors (author_id),
      FOREIGN KEY (book_id) REFERENCES Books (book_id)
    );
    

    我在设计标记系统时也更喜欢自然键:

    CREATE TABLE Tags (
      tag VARCHAR(20) PRIMARY KEY
    );
    
    CREATE TABLE ArticlesTagged (
      article_id INT NOT NULL,
      tag        VARCHAR(20) NOT NULL,
      PRIMARY KEY (article_id, tag),
      FOREIGN KEY (article_id) REFERENCES Articles (article_id),
      FOREIGN KEY (tag) REFERENCES Tags (tag)
    );
    

    这比使用代理“tag_id”键有一些优势:

    • 您可以确保标签是唯一的,而无需添加多余的UNIQUE 约束。
    • 您可以防止两个不同的标签具有完全相同的拼写。
    • 引用标签的依赖表已经有标签文本;他们无需加入 Tags 即可获取文本。

    【讨论】:

    • 给定这种布局,db 是否足够聪明,只存储一次文本数据?
    • 不,通常字符串会在 Tags 表中存储一次,在 ArticlesTagged 表中存储一次。如果存储很重要,您不会选择这种设计,您会因为我提到的其他优势而选择这种设计。
    • 为什么要有标签表?
    • @Draemon:作为允许标签的查找表。您可能不一定有使用每个标签的文章,但您仍然希望列出允许的标签,例如在您的用户界面中填充菜单。另外,SELECT Tag FROM TagsSELECT DISTINCT Tag FROM ArticlesTagged 更快。
    【解决方案3】:

    每个表都应该有一个主键。它是整数、GUID 还是“设置名称”列都没有关系。类型取决于应用程序的要求。理想情况下,如果要将表连接到另一个表,最好使用 GUID 或整数作为主键。

    【讨论】:

      【解决方案4】:

      是的,有充分的理由。您可以拥有语义上有意义的真实密钥,而不是人为的身份密钥。此外,为多对多表设置单独的自动递增主键也不是一个好主意。您可能出于某些原因想要选择 GUID。

      话虽如此,我通常使用自动递增的 64 位整数作为主键。

      【讨论】:

        【解决方案5】:

        每个表都应该有一个主键。但它不需要是单个字段标识符。以财务系统为例,您可能将日记帐表上的主键作为日记帐 ID 和行号。这将为每一行生成唯一的组合(日记帐 ID 将是其自己表中的主键)

        您的主键需要定义您将如何将表链接到其他表。

        【讨论】:

          【解决方案6】:

          我不认为每个表都需要一个主键。有时您只想“连接”两个表的内容 - 通过它们的主键。

          所以你有一个像users 这样的表和一个像groups 这样的表(每个都有主键),你有一个名为users_groups 的第三个表,只有两个列(用户和组)连接用户和组彼此。

          例如,user = 3 和 group = 6 的行会将主键为 3 的用户链接到主键为 6 的组。

          【讨论】:

          • 链接 users_groups 表中的主键是 (User,Group) 确保没有重复的行。
          【解决方案7】:

          不将主键定义为标识的一个原因是将主键定义为 GUID 或使用外部生成的值填充。

          一般来说,每一个本身具有语义意义的表都应该有主键,而主键应该没有语义意义。实现多对多关系的连接表本身没有意义,因此不需要这样的主键(它的值已经有一个)。

          【讨论】:

          • 您的意思是,不需要额外的代理 PK 列吗?它应该有一个主键约束,包括其他 2 个表的键。
          【解决方案8】:

          要成为一个正确规范化的表,每一行应该只有一个可识别的键。许多表已经具有自然键,例如唯一的发票号。我同意,尤其是在存储如此便宜的情况下,在所有表上都有一个自动编号/身份键几乎没有开销,但在这种情况下,这是真正的键。

          我个人不使用此方法的另一个领域,如果用于参考数据,通常我们有一个描述和一个值

          Code, Description
          'L', 'Live'
          'O', 'Old'
          'P', 'Pending'
          

          在这种情况下,将代码设置为主键可确保没有重复,并且更易于阅读。

          【讨论】:

            【解决方案9】:

            自然主键和代理主键之间的键区别(对不起)是自然键的值包含信息,而代理键的值不包含信息。

            为什么这很重要?嗯,自然主键根据定义保证是唯一的,但它的值通常保证保持不变。当它改变时,你必须在多个地方更新它。

            代理键的值没有实际意义,只是用来标识该行,因此永远不需要更改。它是模型的一个特征,而不是领域本身。

            所以我要说代理键不合适的唯一地方是关联表,它只包含引用其他表中行的列(大多数多对多关系)。该表携带的唯一信息是两行(或多行)之间的关联,并且它已经仅由代理键值组成。在这种情况下,我会选择复合主键。

            如果这样的表有包语义,或者带有关于关联的附加信息,我会添加一个代理键。

            【讨论】:

            • 主键变化时不必多处更新。这就是外键和关系的用途。没有要求永远不要更改主键,如果更改主键导致问题,您应该重新审视您的数据库设计并修复它。
            • 是的,您确实需要更新外键和主键。
            • 不,你真的不知道。当主键更改时,使用此主键的所有外键也会更改(如果您有级联更改,您几乎总是应该这样做)。
            【解决方案10】:

            主键总是一个好主意。它允许非常快速和轻松地加入表格。它帮助可以读取系统表的外部工具进行连接,从而允许不太熟练的人通过拖放创建自己的查询。它还使参照完整性的实现变得轻而易举,这从一开始就是一个好主意。

            【讨论】:

              【解决方案11】:

              我确信为网络巨头工作的一些非常聪明的人会这样做。虽然我不知道为什么他们自己的原因,但我知道 PK-less 表有意义的 2 种情况:

              • 正在导入数据。该表是临时的。插入和全表扫描需要尽可能快。此外,我们需要接受重复记录。稍后我们将清理数据,但导入过程需要工作。
              • DBMS 中的分析。识别一行没有用——如果我们需要这样做,那不是分析。我们只需要一个看起来像表格的非关系、冗余、可怕的 blob。我们将通过编写适当的 SQL 查询来构建汇总表或物化视图。

              请注意,这些案例有充分的理由与非相关性无关。但通常你的表应该是关系表,所以...是的,它们需要一个主键。

              【讨论】:

                猜你喜欢
                • 2011-01-31
                • 2011-01-17
                • 1970-01-01
                • 1970-01-01
                • 2011-09-13
                • 1970-01-01
                • 2020-06-16
                • 2010-11-07
                • 1970-01-01
                相关资源
                最近更新 更多