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

この回答を他の回答の後に投稿するので、言及したことのいくつかを繰り返します。この回答ではなく、最初の適切な回答を受け入れてください。

とはいえ、考慮すべき点がいくつかあります。次の 3 つの質問を検討してください。

  1. 投稿のクエリを実行するたびに、常にすべてのコメントが必要ですか?
  2. コメントを直接クエリしますか (特定のユーザーのコメントをクエリするなど)?
  3. システムの使用率は比較的低いですか?

すべての質問に「はい」と答えられる場合は、コメント配列を埋め込むことができます。他のすべてのシナリオでは、コメントを保存するために別のコレクションが必要になるでしょう。

まず第一に、実際には同時実行安全な方法でアトミックにコメントを更新および削除できます (位置演算子による更新を参照) が、インデックス ベースの挿入など、実行できないことがいくつかあります。

あらゆる種類の大規模なコレクションに埋め込み配列を使用する際の主な懸念は、move-on-update の問題です。db.col.stats().paddingFactorMongoDB は、ドキュメントが必要に応じて拡大できるように、ドキュメントごとに一定量のパディング (「参考文献」を参照) を予約しています。このパディングを使い果たした場合(ユースケースでよくあることです)、ディスク上で増え続けるドキュメントを移動する必要があります。これにより、更新が桁違いに遅くなるため、高帯域幅のサーバーでは深刻な問題になります。関連するものの、それほど重要ではない問題に帯域幅があります。最初の 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"}}})

更新基準は (プロセス全体の) 書き込みロックの一部であるため、これらのメソッドはすべて同時実行に対して安全です。

そうは言っても、おそらくコメント専用のコレクションが必要ですが、それには2番目の選択肢があります. 各コメントを専用のドキュメントに保存するか、たとえばそれぞれ 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

パフォーマンス上の理由から、時間の経過とともにサイズが大きくなる可能性のあるドキュメントは避けるのが最善です。

パディングファクター:

「MongoDBでドキュメントを更新するとき、ドキュメントのサイズが大きくなっていなければ、その場で更新が行われます。ただし、ドキュメントのサイズが大きくなった場合は、ディスク上の新しいディスクの場所を見つけるために、ディスク上で再配置する必要があります。新しい大きなドキュメントを収めるのに十分な連続スペース。移動にはドキュメントのすべてのインデックスを更新する必要があるため、コレクションに多くのインデックスがある場合、書き込みパフォーマンスの問題が発生する可能性があります。」

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 に答える