SQL:您是否需要为Many-Many表提供自动增量主键?

时间:2009-04-26 06:13:42

标签: sql database-design

假设你在艺术家和粉丝之间有很多桌子。在设计表时,你是否设计了这样的表:

ArtistFans
    ArtistFanID (PK)
    ArtistID (FK)
    UserID (FK)

 (ArtistID and UserID will then be contrained with a Unique Constraint 
  to prevent duplicate data) 

或者您是否为两个相关领域使用复合PK:

ArtistFans
    ArtistID (PK)
    UserID (PK)

(The need for the separate unique constraint is removed because of the 
 compound PK)

使用以前的架构是否有任何优势(可能是索引?)?

7 个答案:

答案 0 :(得分:19)

ArtistFans
    ArtistID (PK)
    UserID (PK)

使用自动增量PK在这里没有任何优势,即使父表具有它们也是如此。

我也会在(UserID, ArtistID)上自动创建一个“反向PK”索引:你需要它,因为你将通过两列来查询表。

自动编号/ ID列有它们的位置。在基于物理平台的规范化过程之后,您可以选择它们来改进某些事物。但不是链接表:如果你的脑死亡ORM坚持,那么改变ORM ......

编辑,2012年10月

请务必注意,您仍需要唯一的(UserID, ArtistID)(ArtistID, UserID)索引。添加自动增量只会占用不应使用的更多空间(在内存中,而不仅仅在磁盘上)

答案 1 :(得分:5)

即使您创建了一个标识列,它也不必是主键。

ArtistFans
    ArtistFanId
    ArtistId (PK)
    UserId (PK)

标识列可用于将此关系与其他关系相关联。例如,如果有一个创建者表指定了创建艺术家 - 用户关系的人,则可以在ArtistFanId上使用外键,而不是复合的ArtistId + UserId主键。

此外,某些ORM包需要(或大大改进操作)标识列。

答案 2 :(得分:5)

假设你已经是代理钥匙的奉献者(你的公司很好),那就有可能一路走下去。

有时被遗忘的关键点是关系本身可以具有属性。通常仅仅指出两件事是相关的是不够的;你可能要描述这种关系的本质。换句话说,关系表没有什么特别之处,表明它只能有两列。

如果这些表没有什么特别之处,为什么不像其他表一样对待它并使用代理键?如果您最终必须向表中添加属性,那么您将感谢您的幸运表示层,您不必通过复合键来修改这些属性。

我甚至不会将此称为经验法则,更多的是要考虑的事情。根据我的经验,一些狭隘的大多数关系最终会带来额外的数据,基本上成为自己的实体,值得代理关键。

事实上,添加这些密钥可能会让人感到痛苦。额外列和索引的成本是否值得抢占这个头痛的价值,这实际上取决于项目。

至于我,一旦被咬伤,两次害羞 - 我会从门口寻找代理钥匙。

答案 3 :(得分:2)

我想不出任何理由使用你列出的第一个表格。复合主键很好,并且具有单独的人工主键(以及外键上需要的唯一约束)将花费更多时间来计算和存储空间。

答案 4 :(得分:1)

标准方法是使用复合主键。添加一个单独的自动增量键只是创建一个已经使用你所拥有的替代品。正确的数据库规范化模式将使用自动增量来减少。

答案 5 :(得分:0)

有趣的是,所有答案都有利于变体2,所以我不得不反对并争论变体1;)

回答标题中的问题:不,你不需要它。但...

每个表中都有一个自动增量或标识列,可简化您的数据模型,以便您知道每个表始终都有一个PK列。

因此,从一个表到另一个表的每个关系(外键)总是由每个表的一列组成。

此外,如果您碰巧为表单,列表,报告,日志记录等编写了一些应用程序框架,您只需要处理具有单个PK列的表,这样可以简化框架的复杂性。

此外,额外的id PK列在磁盘空间方面不会花费太多(除了十亿记录加表)。

当然,我需要提一个缺点:在祖父母 - 父子关系中,孩子将失去其祖父母信息并需要JOIN来检索它。

答案 6 :(得分:0)

在我看来,在纯SQL中,id列不是必需的,不应该使用。但是对于像Hibernate这样的ORM框架,使用复合键等管理多对多关系并不简单,特别是如果连接表有额外的列。

因此,如果我要在db上使用ORM框架,我更喜欢将自动增量id列添加到该表,并将引用列的唯一约束放在一起。当然,如果需要,则为非null约束。

然后我像处理项目中的任何其他表一样处理表。