14

我已经阅读了基于文档的数据库的描述,例如,如果您愿意,可以将所有评论嵌入到与帖子相同的文档中的帖子下:

{
   _id = sdfdsfdfdsf,
   title = "post title"
   body = "post body"
   comments = [
      "comment 1 ......................................... end of comment"
           .
           .
           n
   ]
}

我有类似的情况,每条评论可能高达 8KB,每个帖子可能有多达 30 条评论。

尽管在同一个文档中嵌入注释很方便,但我想知道大型文档是否会影响性能,尤其是当 MongoDb 服务器和 http 服务器在不同的机器上运行并且必须通过 LAN 通信时?

4

6 回答 6

12

在其他人之后发布这个答案,所以我将重复提到的一些事情。请接受第一个合适的答案,而不是这个。

也就是说,有一些事情需要考虑。考虑这三个问题:

  1. 每次查询帖子时都会要求所有评论吗?
  2. 您想直接查询评论(例如查询特定用户的评论)吗?
  3. 您的系统使用率会相对较低吗?

如果所有问题都可以用“是”回答,那么您可以嵌入评论数组。在所有其他情况下,您可能需要一个单独的集合来存储您的评论。

首先,您实际上可以以并发安全的方式自动更新和删除注释(请参阅使用位置运算符的更新),但有些事情您不能做,例如基于索引的插入。

对任何类型的大型集合使用嵌入式数组的主要问题是移动更新问题。MongoDB 为每个文档保留一定数量的填充(请参阅 参考资料db.col.stats().paddingFactor)以允许它根据需要增长。如果它用完了这个填充(它通常会出现在你的用例中),它将不得不在磁盘上移动那个不断增长的文档。这使得更新速度变慢了一个数量级,因此对高带宽服务器来说是一个严重的问题。一个相关但不太重要的问题是带宽。如果您别无选择,只能查询整个帖子及其所有评论,即使您只显示前 10 条,您将浪费相当多的带宽,这在云环境中尤其是一个问题(您可以使用 $切片以避免其中一些)。

如果您确实想嵌入这里是您的基本操作:

添加评论 :

db.posts.update({_id:[POST ID]}, {$push:{comments:{commentId:"remon-923982", author:"Remon", text:"Hi!"}}})

更新评论:

 db.posts.update({_id:[POST ID], 'comments.commentId':"remon-923982"}, {$set:{'comments.$.text':"Hello!"}})

删除评论

db.posts.update({_id:[POST ID], 'comments.commentId':"remon-923982"}, {$pull:{comments:{commentId:"remon-923982"}}})

所有这些方法都是并发安全的,因为更新标准是(进程范围的)写锁的一部分。

综上所述,您可能想要一个专门的评论收藏集,但这有第二个选择。您可以将每条评论存储在专用文档中,也可以使用评论桶,例如,每条评论 20-30 条(在此处详细描述http://www.10gen.com/presentations/mongosf2011/schemascale)。这有优点和缺点,所以由你决定哪种方法最适合你想做的事情。如果您每篇文章的评论可能超过几百条,我会选择存储桶,因为您需要分页它们的 skip(N) 游标方法的 o(N) 性能。在所有其他情况下,只需使用每个文档的评论方法。这对于查询其他用例的评论也是最灵活的。

于 2012-06-18T11:28:55.040 回答
7

这在很大程度上取决于您要允许的操作,但单独的集合通常更好。

例如,如果您想允许用户编辑或删除评论,将评论存储在单独的集合中是一个非常好的主意,因为这些操作很难或不可能单独使用原子修饰符来表达,并且状态管理变得痛苦。该文档也涵盖了这一点

嵌入评论的一个关键问题是您将拥有不同的作者。通常,博客文章只能由博客作者修改。可以这么说,通过嵌入的评论,读者还可以获得对该对象的写访问权。

像这样的代码会很危险:

post = db.findArticle( { "_id" : 2332 } );
post.Text = "foo";
// in this moment, someone does a $push on the article's comments
db.update(post);
// now, we've deleted that comment
于 2012-06-18T08:44:41.927 回答
3

For performance reasons it is best to avoid documents that can grow in size over time:

Padding Factors:

"When you update a document in MongoDB, the update occurs in-place if the document has not grown in size. If the document did grow in size, however, then it might need to be relocated on disk to find a new disk location with enough contiguous space to fit the new larger document. This can lead to problems for write performance if the collection has many indexes since a move will require updating all the indexes for the document."

http://www.mongodb.org/display/DOCS/Padding+Factor

于 2012-06-18T10:55:06.183 回答
1

如果您总是检索包含所有评论的帖子,为什么不呢?

如果您不这样做,或者您在查询中检索评论而不是通过帖子(即查看用户页面上的所有用户评论),那么可能不会,因为查询会变得更加复杂。

于 2012-06-18T08:32:02.383 回答
0

简短的回答:是和不是。

假设您正在写一个基于 mongoDB 的博客。您会将您的评论嵌入到您的帖子中。

原因:查询很容易,您只需执行一个请求并获取您需要显示的所有数据。

现在,您知道您将获得带有子文档的大型文档。由于您需要通过 LAN 为它们提供服务,我强烈建议您将它们存储在不同的集合中。

原因:通过网络发送大型文档需要时间。我想,在某些情况下您不需要每个子文档。

TL;DR:两种变体都有效。我建议您将评论存储在单独的表格中。

于 2012-06-18T07:35:31.203 回答
0

我正在做一个需要帖子和评论的类似项目,让我列出两者的要点:

如果您: - 需要删除帖子的特定评论 - 想要显示任何帖子的最新评论(通常在博客的侧边栏中),请保留在单独的文档中

如果您: - 不需要上述任何内容 - 需要在同一查询中获取帖子的所有评论(单独的文档方法将需要从不同文档中获取评论),请保留在同一个文档中

于 2018-11-16T06:34:07.010 回答