【问题标题】:One table which refers to several other tables. Is this a good design?一个表引用其他几个表。这是一个好的设计吗?
【发布时间】:2013-12-24 20:41:08
【问题描述】:

我们有用户可以订阅的三种不同类型(用户、文章、评论)。 每种类型都有一个单独的表。我希望用户能够订阅另一个用户、文章或评论。

订阅表列:

id(integer, AI)
type('String, can be 'article', 'comment', 'user')
ref('integer', indicates the index key to an external table)
user_id('integer', foreign key to the users table)

因此,此行将是 id=101 的用户订阅了 id 为 99 的评论

1 | comment | 99 | 101

id=101 的用户也订阅了 id=88 的文章

1 | article | 88 | 101

你明白了。这是一个好的设计吗?

【问题讨论】:

  • 这是一个很常见的设计。主要的错误是你不能在ref 上实现外键约束,因为它引用的表不同。

标签: database database-design


【解决方案1】:

由于“魔术字符串”元素,我会避免这种方法。您的查询将不得不依靠读取字符串来确定用户是否订阅了某些内容。

我会考虑采用不同的方法并使用仅代表用户的表,然后使用“链接”表来匹配具有特定类型订阅的用户(通过他们的 ID)。

例如:

 Users                UsersInArticles              Articles
 -----------          ----------------             ----------
 UserID               UserID                       ArticleID
 Name                 ArticleID                    Title
 Address                                           Body
 etc...                                            etc..

UsersInArticles 表表示订阅了特定文章(按 ArticleID)的用户(按 UserID)。

这种方法允许您使用外键关系维护关系完整性(例如,您可以确保用户无法订阅数据库中不存在的文章)。

此外,不涉及任何魔术字符串。

使用这种方法,要查找订阅了一篇文章(例如文章 123)的所有用户,您只需执行以下查询(而不是与字符串列进行比较以查找“文章”等)。

SELECT UserID from UsersInArticles WHERE ArticleID = 123

我还怀疑,与使用 varchar 列表示订阅类型相比,此 shema 允许更快的查询。

【讨论】:

  • 我结束了创建不同的表。它更标准。谢谢。
【解决方案2】:

这是一个好的设计吗?

没有。

DBMS 无法为您强制执行参照完整性(通过外键)。而在并发环境中,手动实现引用完整性出奇地难以正确(没有竞争条件)并且具有良好的性能。

相反,您可以只使用多个订阅表(每种类型的“可订阅”项目一个)。或者,如果您希望避免表扩散,请使用多个 FK 或继承,类似于 this(但您不一定需要强制执行 FK 排他性)。

【讨论】:

  • 我结束了创建不同的表。它更标准。谢谢。
猜你喜欢
  • 1970-01-01
  • 2012-02-10
  • 1970-01-01
  • 1970-01-01
  • 2011-09-13
  • 1970-01-01
  • 1970-01-01
  • 2015-12-01
  • 1970-01-01
相关资源
最近更新 更多