【发布时间】:2014-10-15 18:06:11
【问题描述】:
我在设计数据库 (SQL/MySQL) 时遇到问题。假设我们有一个用户,用户可以有很多朋友和很多帖子并填写一些关于他自己的数据。
很明显,对于friends,我们需要一个用于 n:n 关系的 pivot_table,对于 posts,我们需要创建一个具有 user_id (1:n) 关系的额外表。
所以我们需要users、user_friends 和posts 表。这是显而易见的。应该这样处理关系。
但现在让我们假设我们希望用户拥有以下数据:
name - text
description - text
marital status - select only one from list
favourite colour - select only one from list
hobby - select up to 3 from list
对于文本字段(名称、描述),很明显我们只需在 users 表中创建 varchar/text 列即可。
一般问题是:应该如何处理其他字段(从列表中选择)?我应该为它们创建关系还是应该用它们创建标准数据列?
在我看来,没有必要为此创建关系表,因为使用列表(选择)我们只限制用户实际上可以粘贴到数据库中。从理论上讲,我们可以允许用户手动输入他的颜色作为最喜欢的颜色(例如red,如果他输入错误,例如reds,我们将比较它会列出允许的colours)。性别也是如此——在我看来,当我们只拥有女人和男人并为其创建关系时,创建额外的表是没有意义的。
第一个数据库设计:
例如,我可以为属性创建以下列:
marital_status - int
fav_colour - int
hobby_1 - int
hobby_2 - int
hobby_3 - int
还有另一个表(甚至是 PHP 或其他语言中的普通数组),我在其中存储 fav_colour 的值 1 是例如红色,爱好的值 2 是音乐等等(我如何存储并不重要这些值在这里 - 我也可以使用 enum 类型)。
对我来说,这种态度的好处不是创建许多实际上是属性而不是关系的关系(正如我上面提到的),所以工作更少+更容易获取有关用户的信息 - 你不需要使用任何连接什么如果您有用户(例如 20 或 100 个这样的属性),这将很重要,我可以很容易地在用户表中搜索。缺点也很明显 - 数据没有标准化,对于任何多选(例如爱好)我需要创建 3 列,如果将来我决定用户不能选择 1 种颜色而是 2 或 3 种,我需要添加2 个额外的列。
另类数据库设计:
我创建了额外的表:colours、hobbies、marital_statuses,并创建了 3 个数据透视表:user_colours、user_hobbies、user_marital_statuses。缺点:连接多。优点 - 如果我创建了 3 个额外的数据透视表,我可以轻松地允许用户选择多达 10 种颜色,并且我根本不需要重新设计数据库。但也存在缺点 - 搜索困难、工作量大、连接次数多。
详细问题
所以总结一下 - 假设什么解决方案会更好:
- 我可能不会更改一个属性的最大数量(如果我决定允许最多 3 个爱好,这可能永远不会改变)
- 许多字段的选择列表相对较短(其中大多数少于 10 个)
- 我需要在这样的数据库中进行大量搜索。例如,有人想要搜索将 fav_colour 设置为红色并拥有爱好音乐的用户。
如果您有任何其他解决方案或优点/缺点,我很感激与我分享。
【问题讨论】:
-
这是另一个选项。使用attributeName、attributeType、attributeValue、userId 创建一个属性表。这将允许您向用户添加任意数量的属性。避免在任何时候想到所需的新信息时进行破坏性架构更改。
-
@paqogomez:这是一种称为“实体属性值”的反模式,但可能是在这里伤害较小的解决方案。另一种选择是将“动态属性”存储为 JSON 或 XML 文档。但这使得在 SQL 中处理它们变得非常困难。第三种选择可能是升级到 Postgres 并使用 Postgres 的 NoSQL 功能,例如键/值数据类型
hstore或内置 JSON 支持 -
@a_horse_with_no_name 我实际上有一条评论建议使用 NoSQL 选项,但将其删除。我认为这不是 OP 想要去的方向。然而,NoSQL 正是针对这种类型的数据。
-
@a_horse_with_no_name 如果 EAV 是“反模式”,那么在数据库中存储 JSON 或 XML 也是一种反模式,因为它违反了 1NF。
标签: mysql sql database database-design relational-database