例如,有三个表:players
、dungeons
和instances
。
一个player
有很多dungeons
,一个dungeon
有很多instances
,就像一个著名的魔兽世界游戏。每个player
都有一个dungeon_id
作为外键,每个dungeon
都有一个instance_id
作为外键。那将是一种足够的极简主义方法。player
每一个都instance
可以通过dungeon
表访问。这将减少 1 列,但查询时间更长。
另一种方法是作为外键添加player_id
到表中。instances
现在玩家可以直接从instances
表中查询。更短的查询,但外键多一列。
从长远来看,哪种方法更好?在实践中,似乎在逻辑上可能的任何地方都添加外键会更容易。但是这不会导致更紧密的耦合并使代码更难重构吗?
IMO,这将是不好的方法。这是一种循环引用。
由于您有一对多关系,因此映射表将是分开的,地牢、实例和玩家每个都将具有定义其一对多关系的主表和映射表。
如果您在播放器和实例之间有非常频繁的查询,并且输出中不需要地牢表并且数据量很高,那么您可以进行非规范化。
是否创建
player_instance mapping table
取决于上述要求。但希望通过以下方式实现非规范化
index view
理想情况下,实体不应该有外键,应该被认为是主人。所以
player
,dungeon
并且instance
是拥有与他们自己的特征相关的信息/属性/字段的大师。您可以为Enitity-Relations提供一个单独的表。因此,您将拥有player_dungeon
anddungeon_instance
(根据 PS,两者都是一对多)。在这里,如果你想知道instances
属于一个player
,你需要加入这两个表。现在出现了著名的辩论:规范化与非规范化。第一种方法是书本上的,并且会奏效。但是随着表的增长很难扩展(尽管有适当的索引)。因此,您尝试根据这些表上发生的查询量对上述解决方案进行非规范化。
由于您在此处指定了一个查询,我假设这是一个频繁查询(瓶颈)。如果有很多这样的查询,你可以有另一个关系表
player_instance
。现在我们已经解决了延迟的问题,但产生了一个更大的问题:一致性:现在有两种方法可以找到
instances
属于 a 的player
。一种是直接按player_instance
表,另一种是通过player_dungeon
和连接dungeon_instance
。我们必须始终从这两种方法中得到相同的答案。为了确保我们现在需要让我们的写入受到影响。如何?player_dungeon
表之外,我们还需要插入到player_instance
表中(我们必须查询dungeon_instance
以查看映射到该特定地牢的所有实例)。dungeon_instance
玩家时,我们需要将所有现有玩家映射到我们映射到特定地牢的实例。听起来不太好,是吗?我们还没有完成。所有这些操作都应该是原子的(即在事务中),否则会在短时间内出现不一致。
最后,我们需要做出取舍。您想让您的数据库读取速度变慢还是写入受到影响?您是否需要使您的系统响应/可用或一致?决定权在你。
详情请阅读CAP 定理。