MongoDB は、ワーキングセットと呼ばれる頻繁にアクセスするデータをRAMに保存します。データとインデックスのワーキングセットが割り当てられた物理RAMを超えると、ディスクへのアクセスが発生し始め、 RAMからデータが取得されなくなるため、パフォーマンスは低下します。
この問題を解決するには、コレクションをシャーディング します。ただし、シャーディングでは追加のコストと複雑さが発生する可能性があり、アプリケーションではまだ準備ができていない可能性があります。コレクションをシャーディングのではなく、 サブセット パターンを使用してワーキングセットのサイズを縮小 できます。
サブセット パターンは、ドキュメント内にアイテムの大きな配列があるが、それらのアイテムの小さなサブセットに頻繁にアクセスする必要があるシナリオを処理するために使用されるデータ モデリング手法です。この場合、ドキュメントサイズによってワーキングセットがコンピューターのRAM容量を超えることがよくあります。サブセット パターンは、一般的なクエリでデータベースから読み込む必要があるデータ量を減らし、パフォーマンスを最適化するのに役立ちます。
このタスクについて
たとえば、products
というコレクションに保存されている、製品のレビューのリストがあるeコマースサイトを考えてみましょう。このeコマースサイトは、次のスキーマを持つドキュメントを products
コレクションに挿入します。
db.collection('products').insertOne( [ { _id: ObjectId("507f1f77bcf86cd99338452"), name: "Super Widget", description: "This is the most useful item in your toolbox." price: { value: Decimal128("119.99"), currency: "USD" }, reviews: [ { review_id: 786, review_author: "Kristina", review_text: "This is indeed an amazing widgt.", published_date: ISODate("2019-02-18") }, { review_id: 785, review_author: "Trina", review_text: "Very nice product, slow shipping.", published_date: ISODate("2019-02-17") }, [...], { review_id: 1, review_author: "Hans", review_text: "Meh, it's ok.", published_date: ISODate("2017-12-06") } ] } ] )
製品のデータにアクセスする場合、最新のレビューのみが必要になる可能性が高くなります。次の手順は、サブセット パターン を上記のスキーマに適用する方法を示しています。
手順
サブセットを異なるコレクションに分割します。
製品のすべてのレビューを保存する代わりに、コレクションを2 つのコレクションに分裂。1 つは最もアクセスしたデータ用で、もう 1 つはアクセス頻度の低いデータ用です。これにより、配列全体をロードする必要なく、最も関連性の高いデータにすばやくアクセスできます。
最初のコレクションである products
コレクションには、現在のレビューなど、最も頻繁に使用されるデータが含まれています。
db.collection('products').insertOne( [ { _id: ObjectId("507f1f77bcf86cd99338452"), name: "Super Widget", description: "This is the most useful item in your toolbox." price: { value: Decimal128("119.99"), currency: "USD" }, reviews: [ { review_id: 786, review_author: "Kristina", review_text: "This is indeed an amazing widget.", published_date: ISODate("2019-02-18") }, [...], { review_id: 776, review_author: "Pablo", review_text: "Amazing!", published_date: ISODate("2019-02-15") } ] } ] )
products
コレクションには最新の 10 件のレビューのみが含まれています。これにより、全体的なデータの一部またはサブセットのみをロードすることで、ワーキングセットを縮小します。
2 番目のコレクション( reviews
コレクション )には、古いレビューなど、使用頻度の低いデータが含まれています。
db.collection('review').insertOne( [ { review_id: 786, review_author: "Kristina", review_text: "This is indeed an amazing widget.", product_id: ObjectId("507f1f77bcf86cd99338452"), published_date: ISODate("2019-02-18") }, { review_id: 785, review_author: "Trina", review_text: "Very nice product, slow shipping.", product_id: ObjectId("507f1f77bcf86cd99338452"), published_date: ISODate("2019-02-17") }, [...], { review_id: 1, review_author: "Hans", review_text: "Meh, it's ok.", product_id: ObjectId("507f1f77bcf86cd99338452"), published_date: ISODate("2017-12-06") } ] )
追加のレビューが必要な場合はいつでも、reviews
コレクションにアクセスできます。データを分裂場所を検討する場合は、ドキュメントの最も使用されるフィールドを メインのコレクションに保存し、使用頻度の低いデータは 新しいコレクションに保存します。
結果
より頻繁にアクセスされるデータを含む小さいドキュメントを使用することで、ワーキングセットの全体的なサイズを縮小します。これにより、アプリケーションが必要とする最も頻繁に使用する情報のディスクアクセス時間を短縮できます。
注意
サブセット パターンでは、1 つではなく 2 つのコレクションを管理し、サブセットではなくドキュメントに関する包括的な情報を収集する必要がある場合は複数のデータベースをクエリする必要があります。