我的数据库中有以下表,它们具有多对多关系,由连接表表示,该连接表具有每个主表的主键的外键:
小部件:WidgetID(PK),标题,价格
用户:UserID(PK),FirstName,LastName
假设每个User-Widget组合都是唯一的.我可以看到两个选项来构建定义数据关系的连接表:
UserWidgets1:UserWidgetID(PK),WidgetID(FK),UserID(FK)
UserWidgets2:WidgetID(PK,FK),UserID(PK,FK)
选项1有一列主键.但是,这似乎是不必要的,因为存储在表中的唯一数据是两个主表之间的关系,并且这种关系本身可以形成唯一键.因此导致选项2,其具有两列主键,但丢失了选项1具有的一列唯一标识符.我还可以选择向第一个表添加两列唯一索引(WidgetID,UserID).
两种性能方面是否有任何真正的区别,或者是否有任何理由偏好一种方法而不是另一种方法来构建UserWidgets多对多表?
在任何一种情况下,您只有一个主键.第二个是所谓的复合键.引入新专栏没有充分的理由.实际上,您必须在所有候选键上保留唯一索引.添加新列只会带来维护开销.
选择2.
就个人而言,我会在多对多表中使用合成/代理键列,原因如下:
如果您在实体表中使用了数字合成键,那么在关系表上使用相同的合成键可以保持设计和命名约定的一致性.
将来可能的情况是,多对多表本身成为需要对单个行进行唯一引用的从属实体的父实体.
它并没有真正使用那么多额外的磁盘空间.
合成键不是自然/复合键的替代,也不PRIMARY KEY
是因为它是表中的第一列而成为该表,所以我部分同意Josh Berkus的文章.但是,我不同意自然键总是很好的候选者PRIMARY KEY's
,如果要在其他表中用作外键,则当然不应该使用.
选项2使用简单的复合键,选项1使用代理键.在大多数情况下,选项2是首选,并且接近于该模型,因为它是一个很好的候选键.
在某些情况下,您可能需要使用代理键(选项1)
你不是说复合键随着时间的推移是一个很好的候选键.特别是对于时间数据(随时间变化的数据).如果要使用相同的UserId和WidgetId向UserWidget表添加另一行,该怎么办?考虑就业(EmployeeId,EmployeeId) - 它可以在大多数情况下工作,除非有人在以后再次为同一雇主工作
如果您正在创建消息/业务事务或类似的东西,需要更简单的密钥来用于集成.复制可能吗?
如果您想创建自己的审计机制(或类似),并且不希望密钥变得太长.
根据经验,在建模数据时,您会发现大多数关联实体(多对多)是事件的结果.人员占用就业,项目被添加到篮子等.大多数事件都对事件具有时间依赖性,其中日期或时间是相关的 - 在这种情况下,代理键可能是最佳选择.
因此,请选择选项2,但请确保您拥有完整的模型.