如何设计一个灵活的 MySQL 引用多个表的通知架构?
How do I design a flexible MySQL notification schema that references multiple tables?
我决定在另一个 Whosebug post 的启发下开发一个通知系统,它建议我将通知与通知正文分开。因此,我有以下架构:
notifications
id | user_id | notification_object_id | is_read
notification_objects
id | message | type
我以这种方式设置它,这样我就可以创建一个通知对象并将其发送给多个用户,以防通知对象适用于多个人。类型可以按类型将消息压缩到一个通知中,就像 Facebook 所说的那样,"John Doe, John Smith, and 27 other users commented..." 而不是给你 29 个单独的通知。
(table 和列的命名模式适用于 CakePHP 3 的 'contains')
我需要帮助的是如何绑定将在请求中发挥作用的不同用户或对象。用户可能已经发表评论,所以我可能需要发消息的用户的 user_id 并需要将其存储在某处。
除用户外还有其他情况;有人可能想知道评论的 ID,这样他就可以点击通知并直接转到 comment/81。我有很多用例,我想存储不同类型的 id,这些 id 是其他 tables(用户、评论、文章等)的外键,其中一些可能需要两个外键(比如你想要提及“Chris has commented on your article 'How to beg Whosebug for help'”)并在通知中链接 Chris 的 user_id 和文章的文章 ID。
每种不同类型的通知可以有不同的值,并且 table 它需要从中提取信息。从哪里开始创建此模式比较好?
我将尝试从面向对象的角度回答这个问题。当使用 classes 而非 tables 时,您可能会以 AbstractNotificationObject
class 具有基本属性(日期、时间,可能是一条消息)和一些专业化 class,例如 NewCommentNotificationObject
具有附加属性(评论、评论用户)或 NewFriendNotificationObject
.深入到数据库模式,然后您可以应用一种典型的 ORM 模式。
具体table继承(只是为了完整性)
使用 concrete table inhericance 可能不是一个好主意,因为它会归结为每个通知 单独的 table输入 (即 comment_notification_objects
table 或更多)。这不会很好地扩展,并且您将无法使用外键从 notification
table 引用它们。此外,您将无法 select 使用单个查询(没有像 UNION 之类的东西)的一组不同类型的通知。
单一table继承
Single table inheritance 将仅使用 带有类型鉴别器列 的单个 table。这个单一的 table(我们称它为 notification_objects
)需要包含一个 type
列来描述记录实际上是什么类型的通知(您实际上已经在您的架构中拥有它)。您还需要用于特殊通知类型可能具有的所有属性的列(例如,user_id
和 comment_id
列)。
+--------------+
| notification |
+--------------+
| id |
+--| object_id |
| +--------------+
|
| +-----------------------+
| | notification_objects |
| +-----------------------+
+->| id PK |
| date |
| type |
| user_id FK |--...
| comment_id FK |--...
| friend_id FK |--...
| [more fields to come] |
+-----------------------+
优点:
- 使用单个查询加载所有通知
- 使用外键保持参照完整性
缺点:
- 缩放不佳(您需要为每种通知类型添加新列)
- Table 将被稀疏填充(许多列将为 NULL)
当您有一组不定期更改的中等大小的通知类型时,我会推荐此架构。
Classtable继承
Class table inheritance介于两者之间;在这里,您将为每种通知类型创建一个中央 notification_objects
table 和单独的 table(例如,带有 id
的附加 comment_notification_object
table列(这又是 notification_object
table 和 user_id
和 column_id
:
的外键
+--------------+
| notification |
+--------------+
| id |
+--| object_id |
| +--------------+
|
| +----------------------+ +------------------------------+
| | notification_objects | | comment_notification_objects |
| +----------------------+ +------------------------------+
+->| id PK |<--+--| id PK/FK |
| date | | | comment_id FK |--...
| type | | | user_id FK |--...
+----------------------+ | +------------------------------+
|
| +--------------------------------+
| | newfriend_notification_objects |
| +--------------------------------+
+--| id PK/FK |
| friend_id FK |--...
+--------------------------------+
[more TABLES to come...]
Class table 继承还允许您使用单个 select 查询来查询所有通知。根据您需要的数据量,您需要将 JOIN 添加到相应的专用 tables.
优点:
- 在不修改现有结构的情况下扩展 well/Add 新类型
- 使用外键保持参照完整性
缺点:
- 当您需要的字段超过最少的字段集时,您需要加入专门的 tables(可能会影响性能)
当您有很多不同的通知类型或经常扩展您的对象模型并且需要定期 change/add 新通知类型时,我会推荐此模式。
在关系框之外
你的问题明确询问了关系模式,所以我专注于此。跳出这个框框思考时,替代解决方案可能包括:
- 无模式 NoSQL 数据库
- 遵循publish/subscribe架构的消息系统
我决定在另一个 Whosebug post 的启发下开发一个通知系统,它建议我将通知与通知正文分开。因此,我有以下架构:
notifications
id | user_id | notification_object_id | is_read
notification_objects
id | message | type
我以这种方式设置它,这样我就可以创建一个通知对象并将其发送给多个用户,以防通知对象适用于多个人。类型可以按类型将消息压缩到一个通知中,就像 Facebook 所说的那样,"John Doe, John Smith, and 27 other users commented..." 而不是给你 29 个单独的通知。
(table 和列的命名模式适用于 CakePHP 3 的 'contains')
我需要帮助的是如何绑定将在请求中发挥作用的不同用户或对象。用户可能已经发表评论,所以我可能需要发消息的用户的 user_id 并需要将其存储在某处。
除用户外还有其他情况;有人可能想知道评论的 ID,这样他就可以点击通知并直接转到 comment/81。我有很多用例,我想存储不同类型的 id,这些 id 是其他 tables(用户、评论、文章等)的外键,其中一些可能需要两个外键(比如你想要提及“Chris has commented on your article 'How to beg Whosebug for help'”)并在通知中链接 Chris 的 user_id 和文章的文章 ID。
每种不同类型的通知可以有不同的值,并且 table 它需要从中提取信息。从哪里开始创建此模式比较好?
我将尝试从面向对象的角度回答这个问题。当使用 classes 而非 tables 时,您可能会以 AbstractNotificationObject
class 具有基本属性(日期、时间,可能是一条消息)和一些专业化 class,例如 NewCommentNotificationObject
具有附加属性(评论、评论用户)或 NewFriendNotificationObject
.深入到数据库模式,然后您可以应用一种典型的 ORM 模式。
具体table继承(只是为了完整性)
使用 concrete table inhericance 可能不是一个好主意,因为它会归结为每个通知 单独的 table输入 (即 comment_notification_objects
table 或更多)。这不会很好地扩展,并且您将无法使用外键从 notification
table 引用它们。此外,您将无法 select 使用单个查询(没有像 UNION 之类的东西)的一组不同类型的通知。
单一table继承
Single table inheritance 将仅使用 带有类型鉴别器列 的单个 table。这个单一的 table(我们称它为 notification_objects
)需要包含一个 type
列来描述记录实际上是什么类型的通知(您实际上已经在您的架构中拥有它)。您还需要用于特殊通知类型可能具有的所有属性的列(例如,user_id
和 comment_id
列)。
+--------------+
| notification |
+--------------+
| id |
+--| object_id |
| +--------------+
|
| +-----------------------+
| | notification_objects |
| +-----------------------+
+->| id PK |
| date |
| type |
| user_id FK |--...
| comment_id FK |--...
| friend_id FK |--...
| [more fields to come] |
+-----------------------+
优点:
- 使用单个查询加载所有通知
- 使用外键保持参照完整性
缺点:
- 缩放不佳(您需要为每种通知类型添加新列)
- Table 将被稀疏填充(许多列将为 NULL)
当您有一组不定期更改的中等大小的通知类型时,我会推荐此架构。
Classtable继承
Class table inheritance介于两者之间;在这里,您将为每种通知类型创建一个中央 notification_objects
table 和单独的 table(例如,带有 id
的附加 comment_notification_object
table列(这又是 notification_object
table 和 user_id
和 column_id
:
+--------------+
| notification |
+--------------+
| id |
+--| object_id |
| +--------------+
|
| +----------------------+ +------------------------------+
| | notification_objects | | comment_notification_objects |
| +----------------------+ +------------------------------+
+->| id PK |<--+--| id PK/FK |
| date | | | comment_id FK |--...
| type | | | user_id FK |--...
+----------------------+ | +------------------------------+
|
| +--------------------------------+
| | newfriend_notification_objects |
| +--------------------------------+
+--| id PK/FK |
| friend_id FK |--...
+--------------------------------+
[more TABLES to come...]
Class table 继承还允许您使用单个 select 查询来查询所有通知。根据您需要的数据量,您需要将 JOIN 添加到相应的专用 tables.
优点:
- 在不修改现有结构的情况下扩展 well/Add 新类型
- 使用外键保持参照完整性
缺点:
- 当您需要的字段超过最少的字段集时,您需要加入专门的 tables(可能会影响性能)
当您有很多不同的通知类型或经常扩展您的对象模型并且需要定期 change/add 新通知类型时,我会推荐此模式。
在关系框之外
你的问题明确询问了关系模式,所以我专注于此。跳出这个框框思考时,替代解决方案可能包括:
- 无模式 NoSQL 数据库
- 遵循publish/subscribe架构的消息系统