如果我有用户,以及用户组(如本地天文学团体/俱乐部),并且我希望两者都与街道地址有一对多的关系,我可以只有1个地址表,还有两个fk,所以我不必复制表模式?或者更好的做法是只有两个独立的表,user_addresses& user_group_addresses?感谢您的输入和时间,谢谢!
答案 0 :(得分:5)
如果用户和组的地址实际上是相同类型的地址,则可以根据需要使用一个地址表进行引用。
答案 1 :(得分:3)
您描述的具有两个外键的设计称为独占弧。只应填充两个外键中的一个。执行和使用非常尴尬。
例如,地址必须引用一个实体,因此从概念上讲,该列是必需的,并且应该是NOT NULL。但是您不能将两列都设为NOT NULL,因为其中一列不属于给定地址。所以他们必须是可以为空的。然后你必须有其他方法来防止两者都是NULL,并且还防止两者都是非NULL。 MySQL不支持CHECK约束,因此您可以编写触发器或编写自定义应用程序代码来强制执行此规则。
如何创建一个地址表,但要扭转这种关系呢?也就是说,Users和Groups表包含对Addresses表的外键引用,而不是相反的方式。
另一个解决方案是,用户和组都依赖于常用的超级表,称之为“可寻址”或其他东西。就像OO设计中的接口或抽象类一样。那么你的地址也可以有一个可寻址的外键。请参阅other questions I have answered on this subject中的示例。
我还在我的书SQL Antipatterns, Avoiding the Pitfalls of Database Programming中的“多态关联”一章中更详细地介绍了这个问题。
答案 2 :(得分:2)
除非有一种地址类型具有另一种地址类型的特定需求,否则拥有1个地址表要好得多。这更容易维护,还允许您添加功能。例如,如果您当地的天文学团体决定他们想要在某处拥有“事件”,那么您只需创建事件表并引用地址表即可。如果你将它们分解出来,那么每当你有一个有地址的新“实体”时,你就必须创建一个新表。
希望这有帮助。
关于你的评论:我会把参考文献放在一个单独的参考表中。
答案 3 :(得分:2)
数据库设计的首要任务是有效性。在使用单表策略保留所有地址时,会有一个隐含的定义,即地址是属于用户还是组。
因为您不必识别哪些地址是所需的集合(用户或组'),所以双表策略是一种更简单的编程方式,可以防止有人编写错误的代码(SQL)。
例如,我们需要来自用户地址的一些数据:
SELECT * FROM user_address WHERE <other conditions>; // The two-table strategy
/**
* The one-table strategy
*/
SELECT * FROM all_addresses
WHERE user_id IS NOT NULL
AND <other conditions>;
此外,如果我们使用两个表来持久保存地址,那么性能会更好。
在单表策略中,即使该列中存在索引(取决于数据库系统),也可能不会优化“IS NOT NULL”条件。加入是在单表策略中识别用户地址的另一种方式,但它仍然比其他策略付出更多努力。
然而,单桌策略具有其性能优势。如果我们需要收集所有地址(无论用户或组织),这种操作就是性能 系统的瓶颈,您可以考虑使用单表策略。