【问题标题】:Relational to NoSQL Database与 NoSQL 数据库相关
【发布时间】:2012-02-09 14:20:20
【问题描述】:

这个问题是针对所有 NoSQL 和特别是 mongoDB 专家的。我开始为一个项目设计一个关系数据库,但客户希望我们使用可以轻松扩展的数据库。为了实现这一点,我们决定使用 mongoDB。这些天来,我在为 NoSQL 映射关系模型时遇到了麻烦。我有一个用户表,它与许多其他表具有多对多关系,如下所示:

在将其转换为 mongoDB 时,我有几个选项:

选项 1(用户中有完整的行):

users:{
  _id:<user_id>,
  battles:{[battle1, battle2, ...]},
  items:{[item1, item2, ...]},
  locations:{[location1, location2, ...]},
  units:{[unit1, unit2, ...]},
}

battles:{
  <battle_info>
}

locations:{
  <location_info>
}

units:{
  <units_info>
}

items:{
  <items_info>
}

选项2(用户中只有外键):

users:{
  _id:<user_id>,
  battles:{[battle1_id, battle2_id, ...]},
  items:{[item1_id, item2_id, ...]},
  locations:{[location1_id, location2_id, ...]},
  units:{[unit1_id, unit2_id, ...]},
}

battles:{
  <battle_info>
}

locations:{
  <location_info>
}

units:{
  <units_info>
}

items:{
  <items_info>
}

选项 3(其他表中的用户 ID):

users:{
  _id:<user_id>,
}

battles:{
  <battle_info>,
  user:{[user1_id, user2_id, ...]}
}

locations:{
  <location_info>,
  user:{[user1_id, user2_id, ...]}
}

units:{
  <units_info>,
  user:{[user1_id, user2_id, ...]}
}

items:{
  <items_info>,
  user:{[user1_id, user2_id, ...]}
}

选项 1 有很多重复,因为我们要添加其他表的完整行。我在其中看到的一个问题是,如果某个项目或战斗被更新,我们将不得不在用户表中找到它的所有出现并更新它们。但这给了我们一个优势,即始终拥有一个完整的用户对象,该对象可以在登录时交给客户端应用程序。

选项 2 更具相关性,我们在 users 表中只有其他表的 mongoIds。此选项的优点是更新战斗或物品不会有太多成本,因为行被引用而不是复制。另一方面,当用户登录时,我们必须找到所有引用的单位、战斗、物品和位置,以使用完整的用户对象进行响应。

选项3与选项2相反,其中用户表的mongoIds保存在其他表中。这个选项对我没有多大吸引力。

如果有人可以指导我或提出更好的模型,我将不胜感激。

编辑:

基本上这是一个多人游戏,其中多个客户端应用程序将通过网络服务连接到服务器。我们在客户端有一个本地数据库来存储数据。我想要一个模型,服务器可以通过该模型以完整的用户对象进行响应,然后更新或插入客户端应用程序上更改的数据。

【问题讨论】:

  • “更好”是一个目的问题。您对这些数据的访问模式是什么?
  • 基本上这是一个多人在线游戏,其中多个客户端应用程序将通过网络服务连接到服务器。我们在客户端有一个本地数据库来存储数据。我想要一个模型,服务器可以通过该模型以完整的用户对象进行响应,然后更新或插入客户端应用程序上更改的数据
  • 关系型数据库具有很强的扩展能力......不同之处应该在于它们预期保存的数据类型,而不是RDB仅适用于小数据,mongodb适用于大数据的错误先入之见跨度>

标签: php mongodb database-design relational-database nosql


【解决方案1】:

首先,NoSQL 不是一刀切。在 SQL 中,几乎每个 1:N 和 M:N 关系都以相同的方式建模。 NoSQL 的理念是,对数据建模的方式取决于数据及其使用模式。

其次,我同意 Mark Ba​​ker 的观点:扩展很难,它是通过放松约束来实现的。这不是技术问题。我喜欢使用 MongoDB,但出于其他原因(不需要编写丑陋的 SQL;不需要复杂、臃肿的 ORM;等等)

现在让我们回顾一下您的选择: 选项 1 复制的数据比需要的多。您经常需要对 一些 数据进行非规范化,但绝不是全部。如果是这样,获取引用的对象会更便宜。

选项 2/3 它们非常相似。这里的关键是:谁在写?您不希望很多客户端对同一文档具有写访问权限,因为这将迫使您使用锁定机制,和/或将自己限制为仅修改操作。因此,选项 2 可能比 3 更好。但是,如果 A 攻击 B,它们也会触发对用户 B 的写入,因此您必须确保您的写入是安全的。

选项 4 部分非规范化:您的用户对象似乎是最重要的,那么如何:

user { 
 battles : [ {"Name" : "The battle of foo", "Id" : 4354 }, ... ]
 ...
}

这将使显示更容易,例如用户仪表板,因为您不需要了解仪表板中的所有详细信息。注意:数据结构随后会与演示的细节相结合。

选项 5 边缘数据。通常,关系也需要保存数据:

user {
 battles : [ {"Name" : "The battle of foo", "unitsLost" : 54, "Id" : 34354 }, ... ]
}

这里,unitsLost 是特定于用户和战斗的,因此数据位于图表的边缘。与战斗名称相反,此数据未进行非规范化。

选项 6 链接器集合。当然,这样的“边缘数据”可能会变得巨大,甚至可能需要一个单独的集合(链接器集合)。这完全消除了访问锁的问题:

user { 
  "_id" : 3443
}

userBattles {
  userId : 3443,
  battleId : 4354,
  unitsLost : 43,
  itemsWon : [ <some list > ],
  // much more data
}

哪些是最好的取决于您的应用程序的许多细节。如果用户进行了很多点击(即你有一个细粒度的界面),那么像选项 4 或 6 那样拆分对象是有意义的。如果你真的需要一批中的所有数据,部分非规范化没有帮助,所以备选方案 2 更可取。请记住多作者问题。

【讨论】:

  • 感谢您的详细回答。您提出了一个有趣的观点,即并非所有多对多关系在 NoSQL 中都具有相同的结构。我想我必须根据自己的需要来组织它们。
【解决方案2】:

选项 2 是要走的路。

如果您要在 RDB 中执行此操作,则在某个时间点(当您必须开始水平扩展时),您还需要开始删除 SQL 连接并在应用程序级别连接数据。

即使是 10gen 也建议使用“手动”参考 ID:http://www.mongodb.org/display/DOCS/Database+References

【讨论】:

    猜你喜欢
    • 2011-05-08
    • 2017-03-19
    • 1970-01-01
    • 2011-10-26
    • 2012-12-26
    • 2013-10-29
    • 1970-01-01
    • 2019-04-18
    • 1970-01-01
    相关资源
    最近更新 更多