【问题标题】:Polymorphic relationships vs separate tables per type多态关系与每种类型的单独表
【发布时间】:2019-11-05 16:43:45
【问题描述】:

我正在研究具有某些类型(例如User、Appointment、Task 等)的数据库,这些类型可以有零个或多个 Notes 与每种类型相关联。

我遇到的实现这些关系的可能解决方案是:

  1. 多态关系
  2. 每种类型的单独表格

多态关系

许多人认为这是最容易实现的解决方案,并且似乎是遵循 Active Record 模式的框架最常见的实现,我将添加一个数据为 morphable 的表:

我的notable_type 可以让我区分Note 所涉及的类型(User、Appointment、Task),而notable_id 可以让我获得个人type记录在相关的type 表中。

优点:

  • 易于扩展,可轻松将更多模型与多态类关联
  • 限制表膨胀
  • 一个类可以被许多其他类使用 (DRY)

缺点

  • 随着数据的增长,更多类型会使查询变得更加困难和昂贵
  • 不能有外键
  • 缺乏数据一致性

每种类型的单独表格

或者,我可以为每种类型创建一个表,该表只负责与该类型关联的Notes。 type_id 外键可以让我快速获取个人 type 记录。

许多在线认为是代码异味,许多文章提倡避免多态关系以支持替代方案(例如here 和here)。

优点:

  • 允许我们有效地使用外键
  • 高效的数据查询
  • 保持数据一致性

缺点:

  • 增加表膨胀,因为每种类型都需要单独的表
  • 产生多个类,每个类代表单独的type_notes 表

想法

多态关系当然是这两个选项中实现起来更简单的一个,但缺少外键约束以及因此可能出现的一致性问题让人感觉不对。

每个带有外键的notes 关系(user_notes、task_notes 等)的表似乎是正确的方法(与设计模式保持一致)但可能会导致很多表(添加其他 types可以有notes 或添加类似于notes 的类型[例如events])。

感觉我的选择是要么简化表结构但放弃外键并增加查询开销,要么增加具有相同结构的表数量但简化查询并允许外键。

根据我的情况,以上哪种情况更合适,或者我应该考虑其他替代方案吗?

【问题讨论】:

    标签: mysql laravel database-design database-schema polymorphic-associations


    【解决方案1】:

    什么是“表格膨胀”?您是否担心桌子太多?我处理过的许多实际数据库都有 100 到 200 个表,因为这就是它所需要的。

    如果您关心添加多个表,那么为什么要为User、Appointment 和Task 设置单独的表?如果你有一个User 的多值属性,例如每个用户有多个电话号码,你会为电话创建一个单独的表,还是尝试以某种方式将它们全部组合到用户表中?或者有一个用于用户电话、约会受邀者和任务里程碑的多态“属于其他事物的事物”表?

    答案:不,您将创建一个 Phone 表,并使用它仅引用 User 表。如果 Appointments 有受邀者,则会有自己的表(可能是约会和用户之间的多对多)。如果任务有里程碑,那也会有自己的表格。

    正确的做法是对数据库表进行建模,就像在应用程序中建模对象类型一样。您可能想阅读SQL and Relational Theory: How to Write Accurate SQL Code 3rd Edition by C. J. Date 之类的书,以了解更多关于表格与类型相似的信息。

    您已经本能地知道,您无法创建外键这一事实是一个危险信号。外键必须准确引用一个父表。这应该是一个线索,表明创建多态外键不是有效的关系数据库设计。一旦您开始将表及其属性视为具体类型(如 SQL 和关系理论中所述),这将变得显而易见。

    如果你必须创建一个笔记表,你可以让它引用一个名为“Notable”的表,它类似于User、Appointment和Task的超类。然后这三个表中的每一个都将引用Notable 的主键。这模仿了多态的面向对象结构,您可以让类 Note 通过其超类类型引用对象。

    但是恕我直言,这比它需要的要复杂得多。我将为UserNotes、AppointmentNotes 和TaskNotes 创建单独的表。我不会因为多了三个表而烦恼,它使您的代码更加清晰和可维护。

    【讨论】:

    • 我想表格膨胀可能是不必要的/过多的表格?我过去通常创建单独的表,但在需要共享类型之前我没有遇到过这种情况,所以我的“关注”是创建多个结构相同、保存相同数据但相关的表分离父类型。这感觉就像它打破了规范化规则。我一定会读那本书,谢谢推荐。
    【解决方案2】:

    我认为你应该考虑这两件事,然后才能做出决定。

    1. 性能。大量读取,大量写入?测试哪个更好。
    2. 模型的增长。是否可以轻松扩展?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-17
      • 1970-01-01
      • 2014-01-10
      • 2018-09-17
      • 2016-06-29
      • 2014-01-22
      • 1970-01-01
      • 2021-04-13
      相关资源
      最近更新 更多