多态关系与每种类型的单独表

Unf*_*lux 6 mysql database-design polymorphic-associations database-schema laravel

我的工作其中有一些类型的数据库(如在UserAppointmentTask它可以有零个或多个等)Notes与每个类型相关联。

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

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

多态关系

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

显着

Mynotable_type将允许我区分相关的类型 ( User, Appointment, Task) Note,而 thenotable_id将允许我获取type相关type表中的单个记录。

优点:

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

缺点

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

每种类型的单独表

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

用户备注

被许多在线人视为代码异味,许多文章主张避免多态关系而支持替代方案(例如此处此处)。

优点:

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

缺点:

  • 增加表膨胀,因为每种类型都需要一个单独的表
  • 结果在多个类中,每个类代表单独的type_notes

想法

多态关系当然是两个实现选项中更简单的一个,但是缺少外键约束并因此潜在的一致性问题感觉是错误的。

每一个表notes的关系(user_notestask_notes外键等)似乎是正确的方式(与设计模式保留),但可能会导致大量的表(除了其他types可有notes或添加相似类型notes[例如events])。

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

鉴于我的情况,以上哪一个更合适,或者我应该考虑其他选择吗?

Bil*_*win 11

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

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

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

正确的做法是像对应用程序中的对象类型建模一样对数据库表进行建模。您可能喜欢阅读CJ Date的《SQL 和关系理论:如何编写准确的 SQL 代码第 3 版》这样的书,以了解有关表如何类似于类型的更多信息。

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

如果必须创建一个音符表,你可以把它引用称为“显着的”一个表,就像是一个超类UserAppointmentTask。然后这三个表中的每一个也将引用 的主键Notable。这模仿了多态的面向对象结构,您可以让类 Note 通过其超类类型引用对象。

但恕我直言,这比它需要的更复杂。我只想创建单独的表UserNotesAppointmentNotesTaskNotes。我并没有因为多三个表而烦恼,它使您的代码更加清晰和可维护。