【问题标题】:Is it fine to have foreign key as primary key?将外键作为主键可以吗?
【发布时间】:2012-06-11 15:19:30
【问题描述】:

我有两张桌子:

  • 用户(用户名、密码)
  • 个人资料(profileId、性别、出生日期……)

目前我正在使用这种方法:每个配置文件记录都有一个名为“userId”的字段作为外键,它链接到用户表。当用户注册时,他的个人资料记录会自动创建。

我对朋友的建议感到困惑:将“userId”字段作为 foreignprimary 键并删除“profileId”字段。哪种方法更好?

【问题讨论】:

  • 实体框架为零或一(和一)对一关系生成(代码优先)。所以……这是可能的。这是最好的方法吗?那是另一个问题。但它是有效的。我在创建自己的数据库时从未这样做过(但我什至从未想过)。
  • 在您的情况下,最好保留两个键,保留两个键都没有害处。

标签: database foreign-keys primary-key


【解决方案1】:

外键几乎总是“允许重复”,这会使它们不适合作为主键。

相反,找到一个唯一标识表中每条记录的字段,或添加一个新字段(自动递增整数或 GUID)作为主键。

唯一的例外是具有 one-to-one 关系的表,其中链接表的 foreign 键和 primary 键是相同的。

【讨论】:

  • 由两个外键组成的复合主键也非常适合实现多对多关系。
  • @rezadru:我不同意 rightfold,但代理键几乎总是更好的选择。
  • 外键并没有说明它是一对多(或“允许重复”)。关键约束和唯一性是数据库中的两个独立概念,可以像添加索引一样轻松混合(这将是第三个独立概念)。
  • 我也同意@RobertHarvey - 在某些情况下,代理键也是更好的选择。例如,您可以有一个映射出多对多关系的中间表,其主键用作另一个表的一部分。由于没有代理键,所有标记为主键的外键最终都会使您的其他表膨胀。但是,如果您有代理键,则传递的所有内容都是一个键。在我看来,它更简单高效。
【解决方案2】:

如果表是一对多关系,主键总是需要唯一,外键需要允许非唯一值。如果表是通过一对一关系而不是一对多关系连接的,则使用外键作为主键是完全可以的。如果您希望同一用户记录有可能拥有超过 1 条相关的个人资料记录,请使用单独的主键,否则请坚持您拥有的。

【讨论】:

    【解决方案3】:

    是的,主键是外键是合法的。这是一个罕见的结构,但它适用于:

    • 1:1 的关系。这两个表不能合并为一个,因为不同的权限和特权仅适用于表级别(截至 2017 年,这样的数据库会很奇怪)。

    • 1:0..1 关系。个人资料可能存在也可能不存在,具体取决于用户类型。

    • 性能是一个问题,设计充当分区:与用户表相比,配置文件表很少被访问,托管在单独的磁盘上或具有不同的分片策略。如果下划线存储是柱状的,则没有意义。

    【讨论】:

    • 如果经常加入表会有负面的性能,这导致正常建议1个表更好。在某些情况下,数据始终是单独访问的,而不是连接的,拥有两个具有 1:1 关系的表可能会给组织带来好处。
    【解决方案4】:

    是的,在这些表之间存在一对一关系的情况下,外键可以是主键

    【讨论】:

    • 这对于超类型-子类型设计也很有用。子类型表的主键应该是对超类型表的外键引用。
    【解决方案5】:

    我不会那样做。我会将profileID 保留为表Profile 的主键

    外键只是两个表之间的引用约束

    有人可能会争辩说,作为从其他表中引用它的任何外键的目标,主键是必要的。外键是任何表中的一个或多个列的集合(不一定是该表的候选键,更不用说该表的主键),它可以保存在某些表的主键列中找到的值其他表。所以我们必须有一个主键来匹配外键。 还是我们必须?主键/外键对中的主键的唯一目的是提供一个明确的连接 - 以保持对包含被引用主键的“外”表的引用完整性。这可确保外键所引用的值始终有效(如果允许,则为 null)。

    http://www.aisintl.com/case/primary_and_foreign_key.html

    【讨论】:

    • 也许 - 如果您在 User.UserID 和 Profile.UserID 之间有 FK 约束,那么强烈建议在 Profile.UserID 上有一个索引。为什么不将其作为表 Profile 上的主聚集索引,为数据库引擎节省第二个索引和一大堆不必要的工作?
    【解决方案6】:

    建立一对一的关系通常被认为是不好的做法。这是因为您可以只在一个表中表示数据并获得相同的结果。

    但是,在某些情况下,您可能无法对所引用的表进行这些更改。在这种情况下,使用外键作为主键没有问题。拥有一个由自动递增的唯一主键和外键组成的复合键可能会有所帮助。

    我目前正在开发一个用户可以登录并生成注册码以与应用程序一起使用的系统。由于我不会进入的原因,我无法简单地将所需的列添加到用户表中。因此,我将使用代码表进行一对一的路由。

    【讨论】:

    • 我基本同意你的观点,将所有数据作为附加列放在同一个表中有很多好处。虽然 w.r.t 这个..“你可以只在一个表中表示数据并获得相同的结果”..:拥有一个单独的表可能很有用,例如在这里如果配置文件表条目是可选的。例如,每个银行客户可能都没有网上银行注册。在这种情况下,IB 注册表可用于限制其他表具有更多的子记录。同样,这里也可以使用 IB 注册表的新 PK 来完成。
    • @Teddy 同样,我非常同意你所说的。但是,在原始问题中,他们声明“......他的个人资料记录是自动创建的......”暗示个人资料表不是可选的。在配置文件表是可选的情况下,将其作为单独的表是可行的。但话又说回来,他们可以只在同一个表中使用可为空的列。
    • 使用单独的第二张表,我们可以防止进入第三张表,只有在第二张表中有条目的人才允许进入。
    • 当然可以,但是如果我们合并 1 到 1 个表,我们可以防止具有空值的人访问第三个(技术上现在是第二个)表。但是 OP 提出的问题包含“......注册时......他的个人资料记录是自动创建......”这一行,这使得这变得多余。
    • 我考虑这一点的主要原因是,在数据仓库中,将事实表和维度表分开是一种很好的做法。在使用 PowerPivot、PowerBI 和 Tableau 等软件时,单独的事实表和维度表是有用的提示。
    【解决方案7】:

    这取决于业务和系统。

    如果您的 userId 是唯一的并且始终是唯一的,您可以使用 userId 作为您的主键。但是,如果您想扩展您的系统,事情就会变得困难。我建议您在表用户中添加外键以与表配置文件建立关系,而不是在表配置文件中添加外键。

    【讨论】:

      【解决方案8】:

      简短回答:取决于.... 在这种特殊情况下,它可能没问题。但是,专家几乎每次都会反对它。包括你的情况。

      为什么?

      当表中的键与相关表无关(源自另一个表)时,它们在表中很少是唯一的。例如,项目 ID 在 ITEMS 表中可能是唯一的,但在 ORDERS 表中可能是唯一的,因为同一类型的项目很可能存在于另一个订单中。同样,订单 ID 在 ORDERS 表中可能是唯一的(可能),但在诸如 ORDER_DETAILS 之类的其他表中不是唯一的,其中可以存在具有多个行项目的订单并查询特定订单中的特定项目,您需要连接两个FK(order_id 和 item_id)作为此表的 PK。

      我不是数据库专家,但如果您可以从逻辑上证明将自动生成的值作为您的 PK,我会这样做。如果这不切实际,那么两个(或更多)FK 的串联可以作为您的 PK。但是,我想不出任何可以将单个 FK 值证明为 PK 的情况。

      【讨论】:

        【解决方案9】:

        它并不完全适用于问题的情况,但由于我最终在这个问题上搜索其他信息并阅读了一些 cmets,我可以说在表中只有一个 FK 并获得唯一值是可能的。 您可以使用具有只能分配 1 次的类的列,它的工作方式几乎与 ID 类似,但是如果您想使用唯一的分类值来区分每条记录,则可以这样做。

        【讨论】:

          猜你喜欢
          • 2013-07-12
          • 1970-01-01
          • 2021-09-06
          • 1970-01-01
          • 1970-01-01
          • 2021-11-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多