【问题标题】:Should I have 1 or 2 tables for user personal addresses and user group addresses?我应该为用户个人地址和用户组地址设置 1 个或 2 个表吗?
【发布时间】:2011-09-19 01:49:53
【问题描述】:

如果我有用户和用户组(如本地天文组/俱乐部),并且我希望两者都与街道地址建立一对多关系,我可以只拥有 1 个地址表和两个 fk 吗?我不必复制表架构?还是只有 2 个单独的表 user_addresses 和 user_group_addresses 是更好的做法?感谢您的投入和时间,谢谢!

【问题讨论】:

    标签: php mysql database database-design doctrine


    【解决方案1】:

    如果用户和组的地址实际上是同一类型的地址,则得到一个地址表,您可以根据需要参考。

    【讨论】:

    • 是否可以有 2 个 fk,并且对于需要与地址建立一对多关系的每个其他对象都可能有一个 fk?还是我应该使用参考表?
    • @blacktie24:和 NullRef 一样,我也在考虑参考表。但也可以只使用外键。取决于你想走多远。例如,如果您添加更多应该引用地址的表,我会选择引用表。
    • 明白了,是的,我打算使用参考表。可以看看底部@Mike Lue 的回答吗?
    【解决方案2】:

    您描述的具有两个外键的设计称为独占弧。应该只填充两个外键之一。执行和使用非常尴尬。

    例如,地址必须引用一个实体,因此从概念上讲,该列是强制性的,并且不应为 NULL。但是您不能将两列都设为 NOT NULL,因为其中之一与给定地址无关。所以它们必须是可空的。然后你必须有一些其他的方法来防止两者都为 NULL,并防止两者都为非 NULL。 MySQL 不支持 CHECK 约束,因此您可以编写触发器或编写自定义应用程序代码来强制执行此规则。

    如果创建一个地址表,但颠倒关系呢?也就是说,Users 和 Groups 表包含对 Addresses 表的外键引用,而不是相反。

    另一种解决方案是让用户和组都依赖于一个共同的超级表,称之为“Addressables”之类的。就像 OO 设计中的接口或抽象类。然后,您的地址也可以具有 Addressables 的外键。请参阅other questions I have answered on this subject 中的示例。

    我还在我的书SQL Antipatterns, Avoiding the Pitfalls of Database Programming“多态关联”一章中更详细地介绍了这个问题。

    【讨论】:

    • 澄清一下,我希望在用户/组和地址之间建立一对多的关系,因此我无法在用户/组中设置 fk。但是,在阅读了您在以下线程中的回复后:stackoverflow.com/questions/441001/…,我觉得对我来说最干净和最简单的选项是选项 #1:为每个目标创建一个额外的表。但是,最终,我仍然不明白您列出的 3 个选项的真正区别是什么。在这一点上是偏好吗?
    • 您还可以在此线程中查看@Mike Lue 的答案吗?这是我最初的解决方案之一,但由于冗余表结构,它似乎效率低下并且可能存在维护问题?
    • @blacktie24:我认为@Mike Lue 的回答很好。将数据拆分为两个表实际上可以更有效。索引数据结构不那么深,等等。此外,如果一种类型的地址有一些不属于另一种类型的自定义属性,您可以使两个表不同。
    【解决方案3】:

    最好有 1 个地址表,除非一种地址类型对另一种地址类型有特殊需求。这更容易维护,还允许您添加功能。例如,如果您当地的天文学小组决定他们想要在某处拥有“事件”,那么您只需创建事件表并引用地址表就可以了。如果您将它们分开,那么每次您有一个具有地址的新“实体”时,您都必须创建一个新表。

    希望这会有所帮助。

    至于您的评论:我会将参考放在单独的参考表中。

    【讨论】:

    • 你能看看我在他们的其他答案中对@hakre 所做的评论吗?
    • @blacktie24 我修改了答案。
    • 正如我对@hakre 的评论,这是有道理的,我打算使用参考表。不过,您也可以看看@Mike Lue 的回答吗?
    • @blacktie24:请检查 Bill Karwin 的答案;)- 我不是专业的 DBA,但看起来他有很多信息要分享。
    • 是的,我一开始还怕像我这样的外行看不懂他的帖子,但他的帖子写得真好!
    【解决方案4】:

    数据库设计的首要任务是有效性。在使用单表策略持久化所有地址时,会隐含地定义地址属于用户还是组。

    因为您不必识别哪些地址是所需的集合(用户或组),所以两表策略是一种更简单的编程方法,可以防止有人编写错误的代码 (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”条件。 Join 是单表策略中识别用户地址的另一种方法,但它仍然比另一种策略更加努力。

    不过,单表策略有其性能优势。如果我们需要收集所有地址(无论是用户还是组),这种操作就是性能 系统瓶颈,可以考虑使用一表策略。

    【讨论】:

      猜你喜欢
      • 2021-05-08
      • 1970-01-01
      • 2018-03-18
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 2018-06-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多