3

下面是一个代表我的问题的数据库设计(它不是我的实际数据库设计)。对于每个城市,我需要知道有哪些餐厅、酒吧和酒店可用。我认为这两种设计不言自明,但是:

第一个设计:在城市与餐厅、酒吧和酒店之间建立一对多的关系。

第二种设计:只在城市和地点之间建立一对多的关系。

哪种设计是最佳实践?第二种设计的关系较少,但我能否获得一个城市的所有餐馆、酒吧和酒店以及自己的数据(property_x/y/z)?

更新:这个问题出了问题,也许是我不清楚的错。

  • 餐厅/酒吧/酒店类是“地方”的子类(在两种设计中)。
  • 餐厅/酒吧/酒店类必须有父“地方”
  • 餐厅/酒吧/酒店类有自己的特定数据(property_X/Y/X)

数据库设计

4

6 回答 6

3

好设计为先

您的数据以及 SQL 和 ERD 的可读性/可理解性是需要考虑的最重要因素。为便于阅读:

  • 放入. city_id_ place原因:地点在城市中。旅馆不是因为是旅馆而恰好在城市中的地方。

其他需要考虑的设计点是这种结构将来如何扩展。让我们比较添加一个新的子类型:

  • 在设计一中,您需要添加一个新表、与“地点”的关系以及与city
  • 在设计二中,您只需添加一个新表和关系到“地点”。

我会再次选择第二种设计。

性能第二

现在,我猜,但放入city_id子类型的原因可能是您预计它在某些特定用例中更有效或更快,这可能是忽略可读性/可理解性的一个很好的理由。但是,在您测量要部署的实际硬件的性能之前,您不知道:

  • 哪种设计更快
  • 性能差异是否真的会降低整个系统的性能
  • 其他优化方法(调整 SQL 或数据库参数)实际上是否是更好的处理方法。

我认为设计一个是尝试在 ERD 上对数据库进行物理建模,这是一种不好的做法。

过早的优化是软件工程中许多罪恶的根源。

亚型方法

在 ERD 上实现子类型有两种解决方案:

  1. 一个公共属性表,每个子类型一个表,(这是您的第二个模型)
  2. 包含子类型属性的附加列的单个表。

在单表方法中,您将拥有:

  • 一个子类型列,TYPE INT NOT NULL. 这指定该行是餐厅、酒吧还是酒店
  • 额外的列property_Xproperty_Y等等property_Zplace

这是利弊的快速表:

单表方法的缺点:

  • 在单表方法中,扩展列(X、Y、Z)不能为 NOT NULL。您可以实现行级约束,但是您失去了简单 NOT NULL 的简单性和可见性
  • 单个表非常宽且稀疏,尤其是在您添加其他子类型时。你可能会达到最大值。某些数据库上的列数。这会使这种设计非常浪费。
  • 要查询特定子类型的列表,您必须使用WHERE TYPE = ?子句进行过滤,而每个子类型的表是更自然的“FROM HOTEL INNER JOIN PLACE ON HOTEL.PLACE_ID = PLACE.ID”
  • 恕我直言,映射到面向对象语言中的类更加困难且不那么明显。考虑避免这个 DB 是否将被 Hibernate、Entity Beans 或类似的映射

单表方法的优点:

  • 通过合并到单个表中,没有连接,因此查询和 CRUD 操作更有效(但是这种微小的差异会导致问题吗?)
  • 不同类型的查询是参数化的(WHERE TYPE = ?),因此在代码中而不是在 SQL 本身(FROM PLACE INNER JOIN HOTEL ON PLACE.ID = HOTEL.PLACE_ID)中更易于控制。

没有最佳设计,您必须根据您最常执行的 SQL 和 CRUD 操作的类型以及可能的性能进行选择(但请参阅上面的一般警告)。

建议

在所有条件相同的情况下,我建议默认选项是您的第二个设计。但是,如果您有我上面列出的那些最重要的问题,请选择其他实现。但不要过早优化。

于 2013-02-04T09:48:39.837 回答
0

他们两个,一个都没有。

如果我需要选择一个,我会保留第二个,因为之后需要创建的外键和索引的数量。
但是,更好的方法是:创建一个包含各种场所(酒吧、餐馆等)的表,并为每一行分配一个具有该场所类型值的列(应用具有预期类型的​​ COMPRESS子句在列)。它将提高结构的性能和可读性,并且更易于维护。

希望这可以帮助。:-)

于 2013-02-01T18:42:21.387 回答
0

您不会在任何子表中显示备用列。我认为您不应该将类型数据拆分为“酒吧”、“餐厅”等表名 - 这些应该是位置表内的类型。

我认为你应该有一个地址表 - 其中一列是城市。然后每个地方都有一个地址,您可以在需要时轻松按城市分组。(或州或邮政编码或国家等)

于 2013-02-01T18:58:32.627 回答
0

我认为最好的选择是第二种。在第一个设计中,可能会出现数据错误,因为一个地方可以分配给一个城市(例如 A)中的特定餐厅(或任何其他类型),同时可以分配给不同城市的另一家餐厅(例如 B)。在第二种设计中,一个地方总是绑定到一个特定的城市。

于 2013-02-01T19:02:19.083 回答
0

第一:
两种设计都可以为您提供所有适当的数据。

第二:
如果所有扩展类都将实现该位置(这对您的实现来说听起来很明显),那么将它作为父对象的一部分包含在内是一个更好的做法。这将建议选项

2。Thingy:
事情是即使很难找到每个特定 PLACE 的类型,更容易知道类型(孩子)总是一个地方(父母)。您可以在可视化选项 2 的结果集时想到这一点。考虑到这一点,我推荐第一种方法。

注意:
第一个没有更多的关系,它只是拆分它们。

于 2013-02-07T03:40:32.243 回答
0

如果 bar、restaurant 和 hotel 具有不同的属性集,那么它们是不同的实体,应该由 3 个不同的表表示。但是为什么你需要地方表呢?我的建议是放弃它并为您的 3 个实体提供 3 个表,仅此而已。

在代码中,将公共属性收集到父类中比在每个子类中重复它们更有条理和效率 - 当然。但正如 spathirana 上面评论的那样,数据库设计不像 OOP。当然,您可以通过将地点的共同属性粘贴到“地点”表中来节省列名的重复。但它也会增加复杂性: - 每当您想引用酒吧、餐厅或酒店时,您必须加入该表 - 每当您想添加新的酒吧、餐厅或酒店时,您必须插入两张表 - 您必须当...等时更新两个表

有 3 个没有 place 表的表也可能是性能最优化的设计。但这不是我的来历。我正在考虑干净、简单的数据库设计,其中单个实体意味着单个表中的单个行。关系数据库中没有“is-a”关系。外键关系是“has-a”。好的,我敢肯定有例外,但你的情况也不例外。

于 2013-02-07T15:45:53.223 回答