27

我正在观看一个截屏视频,作者说在连接表上有一个主键不好,但没有解释原因。

示例中的连接表在 Rails 迁移中定义了两列,作者为每一列添加了索引,但没有主键。

为什么在这个例子中有一个主键不好?

create_table :categories_posts, :id => false do |t|
  t.column :category_id, :integer, :null => false
  t.column :post_id, :integer, :null => false
end
add_index :categories_posts, :category_id
add_index :categories_posts, :post_id

编辑:正如我向 Cletus 提到的,我可以理解自动编号字段作为主键的潜在用途,即使对于连接表也是如此。但是在我上面列出的示例中,作者明确避免在“create table”语句中使用语法“:id => false”创建自动编号字段。通常,Rails 会自动将自动编号 id 字段添加到像这样在迁移中创建的表中,这将成为主键。但是对于这个join table,作者特意阻止了。我不确定他为什么决定采用这种方法。

4

8 回答 8

56

一些注意事项:

  1. category_id 和 post_id 的组合本身是唯一的,因此额外的 ID 列是多余和浪费的
  2. 截屏视频中的短语“拥有主键不好”是不正确的。你仍然有一个主键——它只是由两列组成(例如 CREATE TABLE foo( cid, pid, PRIMARY KEY( cid, pid ) )。对于习惯于在任何地方添加 ID 值的人来说,这可能看起来奇怪,但在关系理论中它是非常正确和自然的;截屏作者最好说“将一个名为'ID'的隐式整数属性作为主键是不好的”。
  3. 拥有额外的列是多余的,因为无论如何您都会在 category_id 和 post_id 的组合上放置一个唯一索引,以确保不会插入重复的行
  4. 最后,虽然常见的命名法是称它为“复合键”,但这也是多余的。关系理论中的“键”一词实际上是唯一标识行的零个或多个属性的集合,因此可以说主键是category_id,post_id
  5. 将 MOST SELECTIVE 列 FIRST 放在主键声明中。对 b(+/*) 树的构建的讨论超出了这个答案的范围(对于一些较低级别的讨论,请参见:http ://www.akadia.com/services/ora_index_selectivity.html )但在你的情况下,您可能希望在 post_id、category_id 上使用它,因为 post_id 在表中出现的频率会降低,从而使索引更有用。当然,由于表很小,而索引本质上是数据行,所以这不是很重要。在更广泛的情况下,表格更宽。
于 2009-05-19T01:54:09.970 回答
3

DBA 会告诉您,在这种情况下,主键实际上是两个 FK 列的组合。由于 Rails/ActiveRecord 不能很好地处理复合 PK(至少默认情况下),这可能是原因。

于 2009-05-19T01:05:43.717 回答
3

基本上是因为不需要它。两个外键字段的组合足以唯一地标识任何行。

但这仅仅说明了为什么它不是一个好主意……但为什么它会是一个坏主意?

考虑添加标识列会增加的开销。该表将占用 50% 以上的磁盘空间。更糟糕的是指数情况。使用身份字段,您必须维护身份计数以及第二个索引。您将使磁盘空间增加三倍,每次插入所需执行的工作量增加三倍。唯一的优点是 DELETE 命令中的 WHERE 子句稍短。

另一方面,如果复合键字段是整个表,那么索引可以是表。

于 2009-05-19T01:40:54.240 回答
3

在任何表、期间(如果 DBMS 是关系 DBMS - 或 SQL DBMS)上没有主键是一个坏主意。主键是数据库完整性的关键部分。

我想如果你不介意你的数据库不准确并且经常提供不正确的答案,那么你可以不用......但大多数人都希望他们的 DBMS 提供准确的答案,对于这些人来说,主键是至关重要的。

于 2009-05-19T01:42:04.517 回答
3

外键的组合可以是一个主键(称为复合主键)。就我个人而言,我更喜欢使用技术主键而不是那个(自动编号字段、序列等)。为什么?好吧,它使识别记录变得更加容易,如果您要删除它,您可能需要这样做。

想一想:如果您要显示所有链接的网页,使用主键来识别记录会更容易。

于 2009-05-19T01:11:31.210 回答
2

首先放置最有选择性的列应该只在 INDEX 声明中相关。在 KEY 声明中,它应该无关紧要(因为,正如已经正确指出的那样,KEY 是一个 SET,并且在一个集合中,顺序无关紧要 - 集合 {a1,a2} 与 {a2 ,a1})。

如果 DBMS 产品使得 KEY 声明中的属性排序产生了影响,那么该 DBMS 产品犯有没有正确区分数据库的逻辑设计(您执行 KEY 声明的部分)和物理设计数据库(执行 INDEX 声明的部分)。

于 2009-05-19T10:34:29.157 回答
2

我想评论以下评论:“说零或更多是不正确的”。

我想指出,添加此评论的文本根本不包含文本“零或更多”,因此我要评论的评论的作者是在批评其他人没有说过的话。

我还想评论说,说“零或更多”是不正确的是不正确的。当今为数不多的仍然费心研究该理论细节的人普遍知道的关系理论实际上需要没有属性的密钥的可能性。

但是当我按下“评论”按钮时,系统回复我说评论需要 50 分(或一些这样的分数)。

一个悲惨的例证,世界似乎忘记了科学不是民主,在科学中,真理不是由碰巧占多数的人决定的,也不是由碰巧拥有“足够声誉”的人决定的。

于 2009-05-19T17:43:30.690 回答
1

单次PK的好处

  • 唯一标识具有单个值的行
  • 如果需要,可以轻松地从其他地方引用关系
  • 有些工具希望你有一个整数值 pk

单一PK的缺点

  • 使用更多磁盘空间
  • 需要 3 个索引而不是 1 个
  • 如果没有唯一约束,您最终可能会为同一关系获得多行

笔记

  • 如果要避免重复,则需要定义唯一约束
  • 在我看来,如果您的表会很大,请不要使用单个 pk,否则会为了方便而牺牲一些磁盘空间。是的,这很浪费,但是在现实世界的应用程序中,谁在乎磁盘上的几 MB。
于 2009-05-19T01:57:22.770 回答