我从性能的角度看,嵌入效果更好: “如果表现是一个问题,请嵌入。” (http://www.mongodb.org/display/DOCS/Schema+Design)和大多数指南总是说应该嵌入包含。
但我不确定是这种情况。假设我们有两个对象:Blog和Post。博客包含帖子。
现在将所有帖子嵌入博客中都会出现以下问题:
考虑到以上所有内容,我会在一个引用Blog的单独集合中发帖。这是正确的结论吗?
(注意:请不要在响应中考虑文档大小限制,假设每个博客最多有1000个帖子)
答案 0 :(得分:12)
1.使用$slice运营商进行分页:
db.blogs.find({}, {posts:{$slice: [10, 10]}}) // skip 10, limit 10
2.过滤也可能:
db.blogs.find({"posts.title":"Mongodb!"}, {posts:{$slice: 1}}) //take one post
3,4。一般来说,我猜你说的是小的性能差异。这不是火箭科学,只是博客最多1000个帖子。
你说:
Is this the correct conclusion?
否,如果您关心性能(一般情况下,如果系统很小,您可以使用单独的文档)。
我做了关于3,4的小型性能测试,结果如下:
-----------------------------------------------------------------
| Count/Time | Inserting posts | Adding to nested collection |
-------------|--------------------------------------------------
| 1 | 1 ms | 28 ms |
| 1000 | 81 ms | 590 ms |
| 10000 | 759 ms | 2723 ms |
---------------------------------------------------------------
答案 1 :(得分:3)
至于3& 4,如果要插入嵌套文档,它基本上是一个更新。
这对您的性能来说非常糟糕,因为插入通常会附加到数据的末尾,而且工作正常且速度很快。另一方面,更新可能会更加棘手。
如果您的更新没有更改文档的大小(意味着您有一个键\值对,只是将值更改为占用相同空间量的新值)那么您将会没事,但是当您开始修改文档并添加新数据,就会出现问题。
问题在于,虽然MongoDB分配的空间超出了每个文档所需的空间,但可能还不够。如果您插入1k大的文档,MongoDB可能会为文档分配1.5k,以确保对文档的微小更改有足够的空间来增长。如果使用的空间超过分配的空间,MongoDB必须获取整个文档并在数据的尾端重新写入。
在获取和重写数据方面显然存在性能影响,这将通过这种操作的频率放大。更糟糕的是,当发生这种情况时,最终会在数据文件中留下漏洞或未使用的空间。
这最终会被复制到内存中,这意味着您最终可能会使用2GB的RAM来存储您的数据集,而实际上数据本身只占用1.5GB,因为它有0.5GB的口袋。通过执行插入而不是更新可以避免这种碎片。它也可以通过数据库修复来修复。
在MongoDB的下一个版本中,将有一个在线压缩功能。
答案 2 :(得分:1)
关于3.和4.我没有证明数据。
BTW 2集合可以更容易编码/使用/管理。您只需在每个“博客”文档中注册blogId,并在所有查询中添加“blogId”:“1234ABCD”