web-dev-qa-db-ja.com

MongoDBスキーマ設計-多数の小さなドキュメントまたは少数の大きなドキュメント

背景
RDBMSデータベースからMongoDBへの変換のプロトタイプを作成しています。非正規化中、2つの選択肢があるように見えます。1つは多数(数百万)の小さなドキュメントに、もう1つは少数(数十万)の大きなドキュメントになります。

それを単純なアナログに要約できるとしたら、これは(Javaのような)顧客文書が少ないコレクションとの違いになります。

 class Customer {
 private String name; 
 private address address; 
 //各CreditCardには数百の支払いインスタンスがあります
 private Set <CreditCard>クレジットカード;
}

または、次のような多数の支払い文書を含むコレクション:

 class Payment {
 private Customer customer; 
 private CreditCard creditCard; 
 private Date payDate; 
 private float payAmount; 
} 

質問
MongoDBは、多数の小さなドキュメントを優先するように設計されていますか?答えは、実行する予定のクエリに大きく依存しますか? (つまり、顧客Xには何枚のクレジットカードがありますか?vsすべての顧客が先月支払った平均金額はいくらですか?)

私はよく見回しましたが、質問に答えるのに役立つMongoDBスキーマのベストプラクティスにつまずきませんでした。

75
Andre

実行しているクエリに対して最適化する必要があります。

これはあなたの説明に基づいた私の最良の推測です。

おそらく、各顧客のすべてのクレジットカードを知りたいので、顧客オブジェクト内にそれらの配列を保持してください。また、支払いごとに顧客の参照が必要になる場合もあります。これにより、支払い文書が比較的小さくなります。

Paymentオブジェクトには、独自のIDとインデックスが自動的に付けられます。おそらく、顧客参照にもインデックスを追加する必要があります。

これにより、顧客オブジェクト全体を毎回保存することなく、顧客による支払いをすばやく検索できます。

「先月のすべての顧客が支払った平均金額はいくらですか」のような質問に答えたい場合は、代わりにマップ/かなりのデータセット。この応答は「リアルタイム」ではありません。これらのmap-reduceには、おそらく「顧客」への「参照」を保存するだけで十分であることがわかります。

あなたの質問に直接答えるために:MongoDBは、多くの小さな文書を好むように設計されていますか、それとも大きな文書を少なくするように設計されていますか?

MongoDBは、インデックス付きエントリを非常に迅速に見つけるように設計されています。 MongoDBは、大きな干し草の山からfew針を見つけるのに非常に優れています。 MongoDBは、not干し草の山の針のmostを見つけるのに非常に優れています。そのため、最も一般的なユースケースを中心にデータを構築し、まれなユースケース用のmap/reduceジョブを作成します。

77
Gates VP

MongoDBのドキュメントによると、多くの小さなドキュメント向けに設計されているようです。

MongoDBのパフォーマンスベストプラクティス

MongoDBのドキュメントの最大サイズは16 MBです。実際には、ほとんどのドキュメントは数キロバイト以下です。テーブル自体よりも、テーブル内の行により近いドキュメントを検討してください。単一のドキュメントでレコードのリストを維持するのではなく、各レコードをドキュメントにします。

から MongoDBスキーマ設計の6つの経験則:パート1

1対2のモデリング

「1対2」の例としては、個人の住所があります。これは埋め込みの良い使用例です。アドレスをPersonオブジェクト内の配列に入れます。

1対多

「1対多」の例は、交換部品発注システムの製品の部品です。各製品には最大数百個の交換部品がありますが、数千個を超えることはありません。これは参照の良い使用例です。製品ドキュメントの配列に部品のObjectIDを入れます。

1から5億

「1から10億」の例は、さまざまなマシンのログメッセージを収集するイベントログシステムです。配列に格納されているものがすべてObjectIDであっても、特定のホストは16 MBのドキュメントサイズをオーバーフローするのに十分なメッセージを生成できます。これは、「親参照」の典型的な使用例です。ホストのドキュメントがあり、ログメッセージのドキュメントにホストのObjectIDを保存します。

19
bmaupin

時間の経過とともに大きく成長するドキュメントは、時限爆弾である可能性があります。ネットワーク帯域幅とRAM使用量は、測定可能なボトルネックになる可能性が高いため、最初からやり直す必要があります。

まず、顧客と支払いの2つのコレクションを考えてみましょう。したがって、粒度はかなり小さく、支払いごとに1つのドキュメントがあります。

次に、クレジットカードなどのアカウント情報をモデル化する方法を決定する必要があります。顧客ドキュメントにアカウント情報の配列が含まれているかどうか、または新しいアカウントコレクションが必要かどうかを考えてみましょう。

アカウントドキュメントが顧客ドキュメントとは別の場合、1人の顧客のすべてのアカウントをメモリに読み込むには、複数のドキュメントを取得する必要があります。これは、余分なメモリ、I/O、帯域幅、CPU使用率につながる可能性があります。それはすぐにアカウントの収集が悪い考えであることを意味しますか?

あなたの決定は支払い書類に影響します。アカウント情報が顧客文書に埋め込まれている場合、どのように参照しますか?個別のアカウントドキュメントには、独自の_id属性があります。アカウント情報が埋め込まれている場合、アプリケーションはアカウントの新しいIDを生成するか、キーにアカウントの属性(アカウント番号など)を使用します。

支払いドキュメントに、固定の時間枠(日など)で行われたすべての支払いを実際に含めることができますか?このような複雑さは、支払い文書を読み書きするすべてのコードに影響します。早すぎる最適化は、プロジェクトにとって致命的です。

アカウントドキュメントと同様、支払いドキュメントに支払いが1つだけ含まれている限り、支払いは簡単に参照されます。新しいタイプのドキュメント、たとえばクレジットは、支払いを参照できます。しかし、クレジットコレクションを作成しますか、または支払い情報にクレジット情報を埋め込みますか?後でクレジットを参照する必要がある場合はどうなりますか?

要約すると、私はたくさんの小さなドキュメントと多くのコレクションで成功しています。 _idを使用して参照を実装しますが、_idのみを使用します。したがって、増え続けるドキュメントがアプリケーションを破壊する心配はありません。各エンティティには独自のコレクションがあるため、スキーマの理解とインデックス付けは簡単です。重要なエンティティは他のドキュメント内に隠れていません。

あなたの発見について聞いてみたい。幸運を!

8
Terris