80

我对这整个 NOSQL 都是新手,最近对 mongoDB 很感兴趣。我正在从头开始创建一个新网站,并决定使用 MONGODB/NORM(用于 C#)作为我唯一的数据库。我一直在阅读很多关于如何正确设计文档模型数据库的内容,并且我认为在大多数情况下我的设计都做得很好。我进入新站点大约 6 个月,我开始看到我需要一遍又一遍地处理的数据复制/同步问题。从我读到的内容来看,这在文档模型中是预期的,并且对于性能来说它是有意义的。IE 将嵌入的对象粘贴到文档中,以便快速阅读 - 无需连接;但当然你不能总是嵌入,所以 mongodb 有一个 DbReference 的概念,它基本上类似于关系数据库中的外键。

所以这里有一个例子:我有用户和事件;两者都有自己的文档,用户参加活动,活动有用户参加者。我决定将包含有限数据的事件列表嵌入到用户对象中。我将用户列表也嵌入到事件对象中作为他们的“参与者”。现在的问题是我必须使用户与也嵌入在事件对象中的用户列表保持同步。当我读到它时,这似乎是首选方法,也是 NOSQL 做事的方式。检索很快,但回退是当我更新主用户文档时,我还需要进入事件对象,可能找到对该用户的所有引用并更新它。

所以我的问题是,这是人们需要处理的一个非常普遍的问题吗?在您开始说“也许 NOSQL 策略不适合我在这里尝试做的事情”之前,这个问题必须发生多少?什么时候不必进行连接的性能优势变成了劣势,因为您很难在嵌入式对象中保持数据同步并对数据库进行多次读取以做到这一点?

4

2 回答 2

68

好吧,这就是与文档存储的权衡。您可以像任何标准 RDMS 一样以规范化的方式存储,并且应该尽可能地进行规范化。只有在性能受到影响的地方,您才应该打破规范化并扁平化您的数据结构。权衡是读取效率与更新成本。

Mongo 有非常高效的索引,可以像传统的 RDMS 一样使规范化更容易(大多数文档存储不会免费为您提供这个,这就是为什么 Mongo 更像是混合而不是纯文档存储的原因)。使用它,您可以在用户和事件之间建立关系集合。它类似于表格数据存储中的代理表。索引事件和用户字段,它应该很快,将帮助您更好地规范数据。

我喜欢绘制扁平结构与保持标准化的效率,当涉及到我更新记录数据所需的时间与读取查询中我需要的内容时。你可以用大 O 表示法来做,但你不必那么花哨。只需根据一些具有不同数据模型的用例在纸上写下一些数字,然后对需要多少工作有一个很好的直觉。

基本上我所做的是首先尝试预测一条记录将有多少更新与读取频率的概率。然后我尝试预测更新的成本与读取的成本是多少,当它被标准化或扁平化(或者可能是我可以想象的两者的部分组合......很多优化选项)时。然后,我可以判断保持不变所节省的成本与从标准化来源建立数据的成本。一旦我绘制了所有变量,如果保持平坦可以节省很多钱,那么我会保持平坦。

一些提示:

  • 如果您需要快速查找以实现快速和原子(完全最新),您可能需要一个偏爱的解决方案,在该解决方案中,您更喜欢扁平化而不是规范化并在更新时受到影响。
  • 如果您需要快速更新并立即访问,则支持规范化。
  • 如果您需要快速查找但不需要完全最新的数据,请考虑在批处理作业中构建标准化数据(可能使用 map/reduce)。
  • 如果您的查询需要快速,并且更新很少,并且不一定要求您的更新可以立即访问或需要在 100% 的时间内进行事务级别锁定(以保证您的更新已写入磁盘),您可以考虑将您的更新写入在后台处理它们的队列。(在此模型中,您稍后可能必须处理冲突解决和和解)。
  • 配置不同的模型。在您的代码中构建一个数据查询抽象层(在某种程度上类似于 ORM),以便您以后可以重构您的数据存储结构。

您可以采用许多其他想法。网上有很多很棒的博客,比如 highscalabilty.org,确保你理解 CAP 定理。

还要考虑一个缓存层,比如 Redis 或 memcache。我会将其中一种产品放在我的数据层前面。当我查询 mongo(它存储所有规范化的内容)时,我使用数据构建一个扁平化的表示并将其存储在缓存中。当我更新数据时,我将使缓存中引用我正在更新的内容的任何数据无效。(尽管您必须花时间使数据失效并跟踪缓存中的数据,考虑到您的缩放因子,这些数据正在更新)。有人曾经说过“计算机科学中最难的两件事是命名事物和缓存失效”。

希望有帮助!

于 2010-10-24T20:09:02.727 回答
0

尝试将 UserEvent 类型的 IList 添加到您的 User 对象。您没有详细说明您的域模型是如何设计的。查看 NoRM 组http://groups.google.com/group/norm-mongodb/topics 以获取示例。

于 2010-10-24T23:18:24.347 回答