好设计为先
您的数据以及 SQL 和 ERD 的可读性/可理解性是需要考虑的最重要因素。为便于阅读:
- 放入.
city_id
_ place
原因:地点在城市中。旅馆不是因为是旅馆而恰好在城市中的地方。
其他需要考虑的设计点是这种结构将来如何扩展。让我们比较添加一个新的子类型:
- 在设计一中,您需要添加一个新表、与“地点”的关系以及与
city
- 在设计二中,您只需添加一个新表和关系到“地点”。
我会再次选择第二种设计。
性能第二
现在,我猜,但放入city_id
子类型的原因可能是您预计它在某些特定用例中更有效或更快,这可能是忽略可读性/可理解性的一个很好的理由。但是,在您测量要部署的实际硬件的性能之前,您不知道:
- 哪种设计更快
- 性能差异是否真的会降低整个系统的性能
- 其他优化方法(调整 SQL 或数据库参数)实际上是否是更好的处理方法。
我认为设计一个是尝试在 ERD 上对数据库进行物理建模,这是一种不好的做法。
过早的优化是软件工程中许多罪恶的根源。
亚型方法
在 ERD 上实现子类型有两种解决方案:
- 一个公共属性表,每个子类型一个表,(这是您的第二个模型)
- 包含子类型属性的附加列的单个表。
在单表方法中,您将拥有:
- 一个子类型列,
TYPE INT NOT NULL
. 这指定该行是餐厅、酒吧还是酒店
- 额外的列
property_X
,property_Y
等等property_Z
。place
这是利弊的快速表:
单表方法的缺点:
- 在单表方法中,扩展列(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 操作的类型以及可能的性能进行选择(但请参阅上面的一般警告)。
建议
在所有条件相同的情况下,我建议默认选项是您的第二个设计。但是,如果您有我上面列出的那些最重要的问题,请选择其他实现。但不要过早优化。