Mongodb 设计,嵌入与关系

Posted

技术标签:

【中文标题】Mongodb 设计,嵌入与关系【英文标题】:Mongo DB Design, embedding vs relationships 【发布时间】:2011-04-18 08:34:40 【问题描述】:

我正在构建一个简单的会计系统,其中用户有很多账单。现在我正在尝试决定 bills 是否应该是它自己的集合,或者嵌套在用户中。我倾向于前者,但我从来没有做过任何 noSQL 的东西,所以我只是通过反复试验,我认为对我来说是有意义的。

我知道 Mongo 有 4mb 的文档大小限制,这让我认为我应该单独收集账单,因为这些账单会每天累积,最终可能会占用大量空间。

我只是在寻找对此事的意见。基本上,我将查询不同日期期间的用户账单(您可以想象会计系统会这样做)。

这并不重要,但我在 Rails3 项目中使用 Mongoid。我想我会做类似的事情:

class User
  references_many :bills
end

class Bill
  referenced_in :user
end

非常感谢任何 cmets 或设计建议。

【问题讨论】:

【参考方案1】:

您可能要考虑的一个问题是,除了用户的会员资格之外,您是否有时需要单独参考帐单?如果是这样,如果他们有独立的存在,那就更简单了。

除此之外,您已经确定的大小限制问题是拆分它们的一个很好的理由。

还可能存在事务问题,如果您正在编写包含许多账单的大用户,如果您从不同的连接合理地同时写入同一用户的更改,会发生什么情况?我对 mongo 知之甚少,不知道它将如何解决这个问题——我的猜测是,如果写入包含不同的添加账单,你会同时得到它们,但如果它们包含现有账单的不同变化,你会得到覆盖——希望其他人会对此发表评论,但至少我会对其进行测试。如果您将账单写入单独的集合,这不是问题。

【讨论】:

【参考方案2】:

1) 关于 4MB 文档的限制,《MongoDB:权威指南》是这么说的:

大于 4MB 的文档(转换为 BSON 时)无法保存到数据库中。这是一个有点武断的限制(将来可能会提高);它主要是为了防止糟糕的架构设计并确保一致的性能。要查看文档 doc 的 BSON 大小(以字节为单位),请从 shell 运行 Object.bsonsize(doc)。

为了让您知道 4MB 是多少,War and Peace 的整个文本只有 3.14MB。

最终,这取决于您预计用户的账单会增长到多大。我希望上面的摘录能让您了解文档大小所施加的限制。

2) 如果您知道您永远不会对账单运行全局查询(此类查询的示例是如果您想检索十最近的账单进入系统)。如果您使用非规范化模式,则必须使用 map-reduce 来检索此类查询的结果。

如果您希望灵活地查询账单的方式,规范化架构(用户和账单在单独的文档中)是更好的选择。但是,由于 MongoDB 不支持连接,因此每次要检索与用户对应的账单时,都必须运行多个查询。

鉴于您提到的用例,我会使用非规范化架构。

3) MongoDB 中的所有更新都是原子的和序列化的。这应该能解决史蒂夫的担忧。

您可能会发现这些幻灯片很有帮助。 http://www.slideshare.net/kbanker/mongodb-meetup

您还可以查看 MongoDB 的生产部署页面。您可能会发现 SF.net 幻灯片很有帮助。

【讨论】:

啊,它只是在写作中......所以这会影响嵌入式文档上的原子选择吗?例如,如果我只是在我的用户文档上对我的账单进行 $push,那么我的用户及其所有账单是否达到 4mb 是否重要,或者只有当账单本身恰好是 4mb 时才重要。我有一种感觉是后者,因此我很安全(因为一张账单不可能包含 4mb 的数据,或者我会在 1 次中写入足够的账单来达到这个数量)听起来对吗?假设,我想我会接受你的建议并去规范化。 嗯...我想我错了,我很确定如果他们的账单超过这个数量,4mb 的限制会影响用户,但是账单中的数据量相当小所以我将尝试使用嵌入式账单并在未来进行一些测试,看看我可以处理什么样的账单容量【参考方案3】:

这个问题已经很久没有解决了,但我正在处理类似的事情,我想我会把我的发现添加给其他研究这个问题的人。

我的理解是 4MB 的文档在 1.8+ 版本中已经扩展为 16MB。这是来自 MongoDB 成员之一的 Banker 的视频演示。我还没有验证这个值,但我相信他的话(因为他希望知道他在说什么)。

关于当同一用户发生多次更新并嵌入账单时会发生什么的问题......再次来自同一个视频演示,提供的答案是 MongoDB 更新信息如此之快以至于它通常不是问题。 MongoDB 实例在更新发生时被锁定,因此多次更新应该不是问题。

我对嵌入文档的担忧是它们不能独立于其父文档来处理。在我看来,这使得嵌入式文档变得毫无价值。它们仅适用于满足特定用例的小众案例。

我个人发现 MongoDB(和 NoSQL DB)对于特定情况很有用,但传统 SQL/RDMS 对于大多数问题仍然更好。如果您是 Craigslist 之类的人,并且架构更改需要您 2 个月才能在存档数据上运行,那么是的,MongoDB 和 NoSQL 是有意义的。但对于绝大多数应用程序,我认为处理这么多数据不会是一个主要问题。

【讨论】:

以上是关于Mongodb 设计,嵌入与关系的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB学习笔记:应用程序设计

Mongodb数据模型

MongoDB 关系

MongoDB

从 SQL Server DB 迁移到 MongoDB:关于是嵌入还是引用的问题

MongoDB