【问题标题】:Should primary key always start from 1?主键应该总是从 1 开始吗?
【发布时间】:2012-07-19 11:01:57
【问题描述】:

我正在迁移一个旧数据库 (oracle),并且像 CountryCodeDeptCodeRoleCodes 这样的表很少,它们的主键是字符串 (Codes),我正在考虑添加 Number 列作为主键,因为它可以与joins 一起快速工作。这些表并不大。

我想知道这些表的主键是否应该从数字“1”开始,或者它可以从 100 开始,只是为了区分黑白表 PK,尽管我认为我不会在报告中显示它们。

【问题讨论】:

  • 您通常可以在表设计器中(在 MSSQL 服务器中)设置初始种子 - 这完全可以。
  • 主键的值是多少并不重要。只要 single 表不包含重复键。两个表的两个主键之间的关系不应该打扰你。您应该只考虑一个表的主键和另一个表的外键(这些必须匹配)。

标签: c# asp.net sql vb.net database-design


【解决方案1】:

对于序列生成的 ID,我建议如果容易做到(取决于您的数据库等)从不同的值开始。您不应该在代码中使用它来区分它们,但它可以使测试更加合理。

在此之前,我遇到过一种情况,我不小心使用了一个表的外键好像它是另一个表的外键。由于ID 是巧合相同,因此通过的测试。发现问题后,我们更改了初始种子,发现测试更加清晰很多

【讨论】:

    【解决方案2】:

    您不应该这样做来区分表格。那是不切实际的。

    并非所有主键都必须从 1 开始,就像订单号一样。

    【讨论】:

    • 如果 PK 从不同的范围开始,那么它有助于测试报告。
    【解决方案3】:

    您用于切换到整数主键的基本原理似乎无效:使用 INT 而不是原始代码(我假设是字符串)所看到的性能提升将可以忽略不计。 PK 总是被索引的,字符串或数字的索引和即时一样好。因此,除非您真的需要 INT,否则我会很想坚持使用原始数据类型并使用原始数据 - 简化数据迁移(这是在做任何工作时都应该考虑的事情)。

    【讨论】:

    • 谢谢,我就是这么想的。另外,可以将 EmpCode(Varchar2) 保留为 PK 吗?该表中大约有 600 行引用了时间表和员工历史表。
    • 我不明白为什么不这样做。在提出参考数据表时,索引的选择比您的编码字段是字符串还是数字更重要。如果整数更快,那仅仅是因为它们是固定的 4 字节值,而字符串的长度可能是随机的(直到字符串字段的最大大小)。因此,如果您的编码字段是(例如)VARCHAR2(10),那么就没有问题。我会担心字符串大小是否明显更长,因为它不是真正的代码(“代码”意味着一个短字符串)。
    • 不过,隐藏主键(如 int 或 guid)的优势在于,您以后可以更改代码列的值,而不会破坏所有具有指向该外键的现有数据代码。
    • EmpCode 长度是 Varchar2(20) 和类似 'UK100'、'UK102'、'FR101' AND 等。在第一个两个字符之后,我必须创建一个序列或一些函数来获得新的价值。
    • @SteveDog - 我想这取决于你为什么有一个代码列。对我来说,如果你有一个代码,这是其他东西的缩写形式,所以你很可能有一个基于 ISO3166 的国家代码列表,它将代码映射到全名。代码不太可能改变。如果你决定坚持一个唯一的数字和 PK (给一个代理键),那么你仍然需要一个唯一的代码索引(有效地给一个自然键)来防止重复代码,所以你得到的很少,如果任何事物。我想这归结为数据:当你知道数据是什么时,你就可以决定最好的PK。
    【解决方案4】:

    例如在 ERP 系统中定义数字范围是很常见的 代表某组项目。

    这两者都可以作为更大数字中的位置,例如

    1234567890
       | |
       index 4 - 6 represents region code
       index 7 - 8 represents dept code... 
    

    或者,我怀疑在你的情况下,零件在同一个地方,比如

    1000 - 1999 Region codes
    2000 - 2999 DeptCode
    3000 - 3999 RoleCode
    

    因此:不,不一定以 1 开头。

    更大的 ERP 系统甚至有数字范围的配置部分!

    现在,从数据库的角度来看:

    是的,您的表应该始终有一个主键! 拥有一个将极大地提高平均情况下的性能。 (但在大多数数据库系统中,如果您不提供一个,则会提供一个 由您看不到且无法处理的 DBMS 设置。一些 DBMS 甚至 创建索引,但那是另一回事)

    【讨论】:

      【解决方案5】:

      我认为保存主键的起始编号或起始值无关紧要。
      重要的是它们将在连接表的 FK 中以与 MAIN 表的 PK 中相同的值表示。

      【讨论】:

        【解决方案6】:

        代理键可以有任何值,只要它们是唯一的。毕竟,这就是使它成为“代理”的原因-值本身没有内在意义,通常甚至不应该向用户显示。话虽如此,您可以考虑使用不同的种子,仅用于测试目的,如Jon Skeet suggested

        话虽如此,您真的需要引入一个新的(代理)键吗?现有的自然键实际上可能会导致 less1 JOINS,并且可能对 clustering 有用。虽然有 legitimate uses 用于代理键,但不要仅仅因为它“时尚”而这样做 - 始终注意您正在做出的权衡并为您的具体需求选择合适的平衡。


        1 它会自动向下“传播”外键,因此您无需为了获取自然键而将子表加入父表 - 自然键已经存在孩子。

        【讨论】:

        • +1,但是使代理成为代理的原因在于它取代了自然键。 (Surrogate 的意思是“替代”或“取代”某物。)
        • @Catcall 我不能说英语,因为它不是我的母语。但在数据库中,代理不仅仅是任何替代品,它是不同质量的替代品。备用键可以很容易地代替主键,但我们不(必然)称它为“代理”。只有当它的值具有某种性质(缺乏意义)时,我们才称它为代理。
        【解决方案7】:

        不管主键从什么 int 开始。 假设代码没有定期更新,我不相信 int 会更快。它在很大程度上取决于它是 varchar 还是已知大小。

        【讨论】:

          【解决方案8】:

          我个人总是将字段名称“Id”作为表的主键,必要时定义为 int 或 bigInt。

          如果表与枚举类型匹配,那么我确保 Id 与可以是任意数字的 EnumeratedType id 匹配 - 所以它不需要从 1 开始。

          如果它不匹配枚举类型,那么我通常会使用从 1 开始的自增键,但这并不总是需要。

          注意 - 如果行数很少,那么对数字和 varchar 进行索引之间的差异将可以忽略不计。

          【讨论】:

          • 但是使用代码的表很大,所以你认为 JOINS 在主键(Varchar2 数据类型)上运行得更快
          • 我不知道你所说的“大”是什么意思,但是是的 - 使用整数而不是 varchar 进行连接会更快 - 表越大,性能差异越大。就我个人而言,我尽量不要加入一个 ID。
          【解决方案9】:

          是的,它从哪个整数开始并不重要,它主要用于定义唯一的行和其他表之间的关系。

          【讨论】:

            猜你喜欢
            • 2019-10-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-12-17
            • 1970-01-01
            • 2015-06-25
            • 1970-01-01
            相关资源
            最近更新 更多