すでに書いたように、SQLの第2正規形のような規則はありません。
ただし、ここにリストするMongoDBの最適化に関連するいくつかのベストプラクティスと一般的な落とし穴があります。
埋め込みの乱用
BSONの制限
一般に信じられていることとは反対に、参照には何の問題もありません。あなたが本の図書館を持っていて、賃貸料を追跡したいとします。このようなモデルから始めることができます
{
// We use ISBN for its uniqueness
_id: "9783453031456"
title: "Schismatrix",
author: "Bruce Sterling",
rentals: [
{
name:"Markus Mahlberg,
start:"2015-05-05T03:22:00Z",
due:"2015-05-12T12:00:00Z"
}
]
}
このモデルにはいくつかの問題がありますが、最も重要なことは明らかではありません。レンタル数に制限があります BSONドキュメントのサイズ制限は16MBであるためです。
ドキュメントの移行の問題
レンタルを配列に格納する際のもう1つの問題は、ドキュメントの移行が比較的頻繁に発生することです。これは、かなりコストのかかる操作です。 BSONドキュメントは、パーティション化されて作成されることはなく、拡張時に事前に割り当てられた追加のスペースが使用されます。この追加のスペースはパディングと呼ばれます。パディングを超えると、ドキュメントはデータファイル内の別の場所に移動され、新しいパディングスペースが割り当てられます。したがって、データを頻繁に追加すると、ドキュメントが頻繁に移行されます。したがって、頻繁に更新することでドキュメントのサイズが大きくなるのを防ぎ、代わりに参照を使用することをお勧めします。
したがって、この例では、単一のモデルを変更して2番目のモデルを作成します。まず、本のモデル
{
_id: "9783453031456",
title:"Schismatrix",
author: "Bruce Sterling"
}
レンタルの2番目のモデルは次のようになります
{
_id: new ObjectId(),
book: "9783453031456",
rentee: "Markus Mahlberg",
start: ISODate("2015-05-05T03:22:00Z"),
due: ISODate("2015-05-05T12:00:00Z"),
returned: ISODate("2015-05-05T11:59:59.999Z")
}
もちろん、同じアプローチを作成者または借受人に使用することもできます。
過剰正規化の問題
しばらく振り返ってみましょう。開発者は、ビジネスケースに関係するエンティティを特定し、それらのプロパティと関係を定義し、それに応じたエンティティクラスを記述し、壁に頭を数時間ぶつけて、トリプルインナーアウターアバブアンドビヨンドJOINの作業を必要とします。ユースケースのために、そしてすべてがその後ずっと幸せに暮らしました。では、なぜ一般的にNoSQLを使用し、特にMongoDBを使用するのでしょうか。誰も幸せに暮らしていなかったからです。このアプローチはひどくスケーリングし、ほとんど排他的にスケーリングする唯一の方法は垂直です。
ただし、NoSQLの主な違いは、回答を得る必要のある質問に従ってデータをモデル化することです。
そうは言っても、典型的なn:mの関係を見て、著者から本までの関係を例として取り上げましょう。 SQLでは、3つのテーブルがあります。エンティティ(本)用に2つです。 および作成者 )と関係用の1つ(どの本の著者は誰ですか? )。もちろん、これらのテーブルを使用して、同等のコレクションを作成することもできます。ただし、MongoDBにはJOINがないため、エンティティの関連ドキュメントを見つけるには、3つのクエリ(最初のエンティティ用、その関係用、および関連エンティティ用)が必要になります。 n:mリレーションの3つのテーブルアプローチは、SQLデータベースが適用する厳密なスキーマを克服するために特別に考案されたため、これは意味がありません。MongoDBには柔軟なスキーマがあるため、最初の質問は、リレーションをどこに保存し、問題を維持するかです。埋め込みの使いすぎを念頭に置いて発生します。著者は今後数年でかなりの数の本を書くかもしれませんが、本の著者が変わることはめったにないので、答えは簡単です。著者を参照として本のデータに保存します
>{
_id: "9783453526723",
title: "The Difference Engine",
authors: ["idOfBruceSterling","idOfWilliamGibson"]
}
そして今、2つのクエリを実行することでその本の著者を見つけることができます:
var book = db.books.findOne({title:"The Difference Engine"})
var authors = db.authors.find({_id: {$in: book.authors})
上記が、コレクションを実際に「分割」するタイミングを決定し、最も一般的な落とし穴を回避するのに役立つことを願っています。
結論
あなたの質問に関して、ここに私の答えがあります
- 前に書いたように:いいえ 、ただし、技術的な制限を念頭に置いておくと、それが理にかなっている場合にアイデアが得られるはずです。
- ユースケースに適合する限り、悪くはありません 。特定のカテゴリとその
_id
がある場合 、関連商品を見つけるのは簡単です。商品を読み込むときに、_id
のように、商品が属するカテゴリを効率的に取得できます。 デフォルトでインデックスが作成されます。 - MongoDBで実行できないユースケースはまだ見つかりませんが、MongoDBでは少し複雑になる可能性があります。私がすべきことは、機能要件と非機能要件の合計を取り、長所が短所を上回っているかどうかを確認することです。私の経験則:「スケーラビリティ」または「高可用性/自動フェイルオーバー」のいずれかが要件のリストに含まれている場合、MongoDBは一見の価値があります。