我想知道你是否有一个网站上有十几种不同类型的商品(商店,餐馆,俱乐部,酒店,活动)需要不同的字段,是否有利于创建一个包含如此定义的列的表
示例商店:
shop_id | name | X | Y | city | district | area | metro | station | address | phone | email | website | opening_hours
或者更类似于此的抽象方法:
object_id | name
---------------
1 | Messy Joe's
2 | Bate's Motel
type_id | name
---------------
1 | hotel
2 | restaurant
object_id | type_id
---------------
1 | 2
2 | 1
field_id | name | field_type
---------------
1 | address | text
2 | opening_hours | date
3 | speciality | text
type_id | field_id
---------------
1 | 1
1 | 2
2 | 1
2 | 3
object_id | field_id | value
1 | 1 | 1st street....
1 | 3 | English Cuisine
当然,如果预定义值,它可能会更抽象(例如:专业可以有自己的列表)
如果我采用抽象方法,它可以非常灵活,但是对于大量连接,查询会更复杂。 但我不知道这是否会影响性能,执行这些“更复杂”的查询。
我很想知道这两种方法的优缺点是什么。我可以想象一下自己,但我没有经验证实这一点。
答案 0 :(得分:77)
答案 1 :(得分:9)
在您的问题中,您至少同时提出了两个主要问题。这两个问题是E-A-V和gen-spec。
首先,我们来谈谈E-A-V。你的最后一个表(object_id,field_id,value)本质上是一个E-A-V。 E-A-V有一个好处,而E-A-V则有下行空间。好处是结构非常通用,几乎可以容纳描述几乎所有主题的任何数据体。这意味着您可以继续进行设计和实施,无需进行数据分析,也无需了解主题,也不必担心错误的假设。缺点是在检索时,您必须在构建数据库之前进行数据分析,以便提出任何意义上的查询。这比检索效率要严重得多。但是你也会在检索效率方面遇到可怕的问题。只有两种方法可以了解这个陷阱:通过它来实践它或从那些拥有它的人那里了解它。我推荐阅读。
其次,你有一个gen-spec案例。您的表(object_id,type_id)捕获gen-spec(泛化特化)模式以及相关表。如果我不得不在酒店和餐馆之间进行概括,我可以称之为“公共住宿”或“场地”。但是我不确定我是否了解你的情况,而且你可能正在驾驶一些比这两个名字更普遍的东西。毕竟,你已经在你的列表中包含了“事件”,并且事件不是我脑海中的一种场所。
在其他回复中,我引用了其他人的关于gen-spec和关系模型的读物 When two tables are very similar, when should they be combined?
但是我不愿意向你发送同一个方向,因为我不清楚你想在构建数据库之前想出一个数据的关系模型。一组数据的关系模型和相同数据的E-A-V模型几乎完全相互矛盾。在你甚至探索如何在关系数据模型中表达gen-spec之前,你似乎必须做出这个选择。
答案 2 :(得分:3)
当你开始需要大量不同的实体时(甚至在......之前),nosql解决方案将比任何一种选择都简单得多。 只需存储每个实体/记录以及您需要的确切字段。
{
"id": 1,
"type":"Restaurant",
"name":"Messy Joe",
"address":"1 Main St.",
"tags":["asian","fusion","casual"]
}
答案 3 :(得分:2)
“抽象”方法更好地称为“标准化”,看起来像第三范式(3NF)。
另一个称为“非规范化”,并且可以是一个有效的性能选项......当您使用规范化方法遇到速度问题时,而不是之前。
答案 4 :(得分:1)
如何在代码中显示列表?我猜Listing
为超类型,Shop
,Restuarant
等作为子类型?
假设这是一个如何将子类型映射到关系数据库的情况。通常有三种选择:
没有普遍正确的解决方案。我的偏好通常是从选项3开始;它提供了一个可以使用的原型结构,很好地规范化并且可以很容易地扩展。它意味着用于检索每个实例的单个连接 - 但是RDBMS针对连接进行了很好的优化,因此在实践中它不会真正导致性能问题。
选项2对于查询(无连接)可能更高性能,但如果其他表需要引用所有超类型实例(外键扩散),则会导致问题。
选项1乍一看似乎是最高效的,尽管有2个警告:(1)改变不具备弹性。如果添加新的子类型(以及不同的属性),则需要更改表结构并进行迁移。 (2)它可能效率低于看起来的效率。由于表填充稀疏,因此某些DB不能特别有效地存储它。因此,它可能比选项1效率低 - 因为查询引擎可以比搜索膨胀的稀疏表空间更快地进行连接。
选择哪个真正归结为了解问题的详细信息。我建议您阅读一些选项:this article是一个很好的起点。
HTH