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

Polymorphic relationships vs separate tables per type

我正在处理具有某些类型(例如 UserAppointmentTask 等)的数据库,这些类型可以有零个或多个 Notes 关联每种类型。

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

  1. 多态关系
  2. 每种类型table

多态关系

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

我的 notable_type 可以让我区分 Note 相关的类型(UserAppointmentTask),而 notable_id 将允许我在相关 type table.

中获取个人 type 记录

优点:

缺点

每种类型Table

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

网上很多人认为这是一种代码味道,许多文章提倡避免多态关系,转而采用替代关系(例如here and here)。

优点:

缺点:

想法

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

A table per notes relationship (user_notes, task_notes etc.) with foreign keys seems the correct way (in keeping with design patterns) but could result在许多 table 中(添加其他可以具有 notestypes 或添加类似于 notes 的类型 [例如 events])。

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

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

我觉得你应该考虑这两件事,然后再做决定。

  1. 性能。大量读取,大量写入?测试哪个更好。
  2. 模型的成​​长。是否容易扩展?

什么是"table bloat"?您是否担心 table 太多?我工作过的许多 real-world 数据库都在 100 到 200 table 之间,因为这就是它所需要的。

如果您担心添加多个 table,那么为什么要为 UserAppointment 和 [=12= 使用单独的 table ]?如果您有 User 的 multi-valued 属性,例如每个用户有多个 phone 号码,您会为 phone 创建一个单独的 table,还是您尝试以某种方式将它们全部组合到用户 table 中?或者为用户 phone、约会受邀者和任务里程碑提供多态 "things that belong to other things" table?

答案:不,您将创建一个 Phone table,并使用它仅引用 User table。如果 Appointments 有被邀请者,那会得到它自己的 table(可能是 appointments 和 users 之间的 many-to-many)。如果任务有里程碑,那也会有自己的 table。

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

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

如果您必须创建一个笔记 table,您可以将其引用一个名为 "Notable" 的 table,它类似于 User 的超级 class 、AppointmentTask。然后这三个 table 中的每一个也会引用 Notable 的主键。这模仿了多态性的 object-oriented 结构,您可以在其中有一个 class 注释通过其 superclass 类型引用一个对象。

但是恕我直言,这比需要的要复杂得多。我只想为 UserNotesAppointmentNotesTaskNotes 创建单独的 table。我对多三个 table 并不感到困扰,它使您的代码更加清晰和可维护。