为什么在连接表上有主键是不好的?

pez*_*ser 21 database migration ruby-on-rails primary-key junction-table

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

示例中的连接表在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
Run Code Online (Sandbox Code Playgroud)

编辑:正如我提到的Cletus,即使对于连接表,我也能理解自动编号字段作为主键的潜在用处.但是,在上面列出的示例中,作者明确避免在"create table"语句中使用语法":id => false"创建自动编号字段.通常,Rails会自动将一个auto-number id字段添加到像这样的迁移中创建的表中,这将成为主键.但是对于这个连接表,作者专门阻止了它.我不确定他为什么决定采用这种方法.

Mat*_*ish 47

一些说明:

  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会在表中不那么频繁出现,从而使索引更有用.当然,由于表太小而且索引本质上是数据行,因此这不是很重要.在更广泛的情况下,表格更广泛.

  • 第六个原因是具有合成主键将导致对表的写入(轻微)性能损失.这是因为您必须生成下一个键并更新另一个索引,每次插入到表中,但由于您不太可能引用合成键,因此您不会获得任何加速读取指数.为了某事而获得任何好处是一个糟糕的权衡. (2认同)