【问题标题】:Why does my database table need a primary key?为什么我的数据库表需要主键?
【发布时间】:2012-08-26 18:44:56
【问题描述】:

在我的数据库中,我有一个用户列表,其中包含有关他们的信息,并且我还有一个功能,允许用户将其他用户添加到候选名单中。我的用户信息存储在一个带有用户 ID 主键的表中,我还有另一个表用于候选名单。候选名单表的设计使其具有两列,基本上只是一对名称的列表。因此,要查找特定用户的候选名单,您可以从第二列中检索所有名称,其中第一列中的 id 是特定值。

问题在于,根据Should each and every table have a primary key? 等许多来源,您应该在数据库的每个表中都有一个主键。

根据此来源http://www.w3schools.com/sql/sql_primarykey.asp - 一个主键,它唯一地标识数据库中的一个条目。所以我的问题是:

  1. 我的数据库中的表有什么问题?为什么需要主键?

  2. 我应该如何给它一个主键?只需创建一个新的自动递增列,以便每个条目都有一个唯一的 id?这似乎没有多大意义。或者我会以某种方式将代表候选名单的多个条目封装到另一个表中的另一个实体中并将其链接起来?我真的很困惑。

【问题讨论】:

  • 只用索引试试,不需要主键。获取关于性能的数字,看看它是否足够快。
  • 谢谢,我会试试的。但是,从适当的关系角度来看,您将如何做这样的事情?您不能创建另一个表来代表一个人的候选名单,因为这还需要适应这样一个事实,即我们不知道该人将添加多少人。所以你不能为每个单独的列 - 你需要一个新行 - 回到相同的情况哈哈!
  • 您创建了一个包含两个用户 ID 作为列的表,因此您可以将一个人与其他人关联起来,如果您想强制唯一性,则创建一个由两个列组成的主键。
  • 您的候选名单很好。它在两列中都有一个主键;它有两个外键,一个用于引用主用户表的每一列。这是一个非常值得尊敬的设计。我认为候选名单的附加“id”列没有任何优点;您仍然需要对两个用户 ID 值进行唯一约束,并且您不太可能(但并非不可能)有任何其他表引用候选清单表的主键。您需要唯一(主键)约束,因此您不必在查询中使用 DISTINCT 以避免输出中出现重复行。

标签: database database-design entity-relationship


【解决方案1】:

如果行是唯一的,您可以有一个两列的主键,尽管这可能取决于数据库。这是一个例子:

CREATE TABLE my_table
(
col_1 int NOT NULL,
col_2 varchar(255) NOT NULL,
CONSTRAINT pk_cols12 PRIMARY KEY (col_1,col_2)
)

如果您已经拥有该表,则示例如下:

ALTER TABLE my_table
ADD CONSTRAINT pk_cols12 PRIMARY KEY (col_1,col_2)

【讨论】:

  • 是的,我猜每一行都是独一无二的。你会怎么做?我能想到的唯一另一种方法是使用包含入围值的 CSV 扩展我的用户信息表 - 尽管我不想这样做,因为搜索会很糟糕!
  • 我添加了一个例子。我不确定这对于不同的数据库有多便携。
【解决方案2】:

主键必须唯一地标识每条记录,并且如前所述,主键可以包含多个属性(1 列或多列)。首先,我建议确保每条记录在您的表中都是独一无二的。其次,据我了解,您在没有主键的情况下离开了表,这是不允许的,所以是的,您需要为其设置键。

【讨论】:

    【解决方案3】:

    在这种特殊情况下,在shortlist 表中多次存储同一对用户 ID 是没有意义的。毕竟,该表模拟了一个集合,而一个元素要么在集合中,要么不在集合中。在集合中有一个元素“两次”是没有意义的1。为防止这种情况发生,请创建一个由这两个用户 ID 字段组成的复合键。

    此复合键是否也是主键,或者您将拥有 另一个 键(将充当代理主键)是 another matter,但无论哪种方式,您都需要此复合键.

    请注意,在支持clustering (aka. index-organized tables) 的数据库下,PK 通常也是一个聚类键,可能会对性能产生重大影响。


    1 与 mutiset 不同。

    【讨论】:

      【解决方案4】:

      具有重复行的表不能充分表示关系。它是一袋行,而不是一组行。如果你让这种情况发生,你最终会发现你的计数将被取消,你的总和将被取消,你的平均值将被取消。简而言之,当您使用数据时,您会从数据中得到令人困惑的错误。

      声明主键是一种防止重复行进入数据库的便捷方法,即使其中一个应用程序出错。您获得的索引是副作用。

      可以通过引用任何候选键来对表中的单行进行外键引用。但是,如果您将其中一个候选键声明为主键,然后使所有外键引用都引用主键,则会方便得多。只是仔细的数据管理。

      现实世界中的实体与该实体的表中对应行之间的一一对应关系超出了 DBMS 的范围。由您的应用程序甚至您的数据提供者通过不为现有实体发明新行并且不让一些新实体从裂缝中溜走来维持这种对应关系。

      【讨论】:

        【解决方案5】:

        好吧,既然您在问,这是一种很好的做法,但在少数情况下(不需要连接数据),它可能不是绝对需要的。最大的问题是你永远不知道需求是否会改变,所以你现在真的想要一个,这样你就不会在事后向 10m 的记录表添加一个.....

        除了一个主键(顺便说一句,它可以跨越多个列)之外,我认为拥有一个作为单个字段的辅助候选键是一种很好的做法。这使得连接更容易。

        首先是一些理论。您可能还记得 HS 或大学代数中对函数的定义是 y = f(x) 其中 f 是一个函数当且仅当对于每个 x 都恰好有一个 y。在这种情况下,在关系数学中,我们会说 y 在这种情况下的 x 上是 functionally dependent

        您的数据也是如此。假设我们正在存储支票号码、支票帐号和金额。假设我们可能有多个支票账户,并且每个支票账户不允许有重复的支票号码,那么金额在功能上取决于 (account, check_number)。通常,您希望将功能上依赖于同一事物的数据存储在一起,而没有传递依赖。主键通常是您指定为主键的功能依赖项。然后,这会识别该行中的其余数据(因为它与该标识符相关联)。将其视为natural primary key. 在可能的情况下(即不使用 MySQL)我喜欢将主键声明为自然键,即使它跨越列。这有时会变得复杂,因为您可能有多个可互换的候选键。例如,考虑:

        CREATE TABLE country (
            id serial not null unique,
            name text primary key,
            short_name text not null unique
        );
        

        这个表真的可以有任何列作为主键。这三个都是完全可以接受的候选键。假设我们有一个国家记录(232,'United States','US')。这些字段中的每一个都唯一地标识记录,因此如果我们知道一个,我们就可以知道其他的。每一个都可以定义为主键。

        我还建议使用第二个人工候选键,它只是用于连接连接的机器标识符。在上面的例子中 country.id 就是这样做的。这对于将其他记录链接到国家/地区表很有用。

        需要候选键的例外情况可能是确实可能出现重复记录。例如,假设我们正在跟踪发票。我们可能会遇到这样一种情况,即某人为两个项目单独开具发票,两个项目中的每一个都显示一个。这些可能是相同的。在这种情况下,您可能想要添加一个人工主键,因为它允许您稍后将事物加入该记录。您现在可能不需要这样做,但将来可能!

        【讨论】:

          【解决方案6】:

          创建复合主键。 要详细了解复合主键是什么,请访问 http://www.relationaldbdesign.com/relational-database-analysis/module2/concatenated-primary-keys.php

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-01-24
            • 1970-01-01
            • 1970-01-01
            • 2020-10-12
            • 2013-01-16
            • 1970-01-01
            相关资源
            最近更新 更多