一括書き込み操作
Overview
MongoDB では、書込み (write) 操作を一括で実行する能力がクライアントに提供されます。一括書き込み操作は単一のコレクションに影響します。MongoDB では、一括書き込み操作に必要な確認応答の許容レベルをアプリケーションが決定できます。
db.collection.bulkWrite()
メソッドでは、一括挿入、アップデート、削除の操作を実行する機能が提供されます。
MongoDB は、db.collection.insertMany()
メソッドによる一括挿入もサポートしています。
順序付き操作と順序なし操作
一括書き込み操作は、 順序付き、順序なしどちらでも可能です。
MongoDB では、順序付きの操作リストを使用し、操作を連続して実行します。いずれかの書き込み操作の処理中にエラーが発生した場合、MongoDB はリスト内の残りの書き込み操作を処理せずに返します。「順序付き一括書き込み」を参照してください。
操作の順序付けられていないリストを使用すると、MongoDB は操作を並列に実行できますが、この動作は保証されません。いずれかの書き込み操作の処理中にエラーが発生した場合、MongoDB はリスト内の残りの書き込み操作の処理を続行します。「順序付けなしの一括書き込みの例」を参照してください。
シャーディングされたコレクションで順序付きの操作リストを実行すると、通常、順序なしのリストの実行よりも時間がかかります。これは、順序付きのリストでは毎回のオペレーションで前のオペレーションの完了を待機する必要があるためです。
デフォルトでは、bulkWrite()
が ordered
操作を実行します。unordered
の書き込み操作を指定するには、オプション ドキュメントで ordered : false
を設定します。
「操作の実行」を参照してください。
bulkWrite() メソッド
bulkWrite()
次の書き込み操作をサポートします。
それぞれの書き込み操作は、配列内のドキュメントとして bulkWrite()
に渡されます。
例
このセクションの例では、pizzas
コレクションを使用します。
db.pizzas.insertMany( [ { _id: 0, type: "pepperoni", size: "small", price: 4 }, { _id: 1, type: "cheese", size: "medium", price: 7 }, { _id: 2, type: "vegan", size: "large", price: 8 } ] )
次の bulkWrite()
の例では、pizzas
コレクションに対してこれらの操作を実行します。
insertOne
を使用して 2 つのドキュメントを追加します。updateOne
を使用してドキュメントをアップデートします。deleteOne
を使用してドキュメントを削除します。replaceOne
を使用してドキュメントを置換します。
try { db.pizzas.bulkWrite( [ { insertOne: { document: { _id: 3, type: "beef", size: "medium", price: 6 } } }, { insertOne: { document: { _id: 4, type: "sausage", size: "large", price: 10 } } }, { updateOne: { filter: { type: "cheese" }, update: { $set: { price: 8 } } } }, { deleteOne: { filter: { type: "pepperoni"} } }, { replaceOne: { filter: { type: "vegan" }, replacement: { type: "tofu", size: "small", price: 4 } } } ] ) } catch( error ) { print( error ) }
完了した操作の概要を含む出力例を示します。
{ acknowledged: true, insertedCount: 2, insertedIds: { '0': 3, '1': 4 }, matchedCount: 2, modifiedCount: 2, deletedCount: 1, upsertedCount: 0, upsertedIds: {} }
その他の例については、「bulkWrite() の例」を参照してください。
シャーディングされたコレクションへの一括挿入に関する戦略
初期データの挿入やルーチン データのインポートをはじめとした大規模な一括挿入操作は、シャーディングされたクラスターのパフォーマンスに影響を与える可能性があります。一括挿入の場合は、次の方法を検討してください。
コレクションの事前分割
シャーディングされたコレクションが空の場合、コレクションには最初のチャンクが 1 つだけあり、そのチャンクは 1 つのシャード上にあります。MongoDB は、データを受信し、分割を作成し、分割されたチャンクを利用可能なシャードに配布するのに時間がかかります。これによるコストを回避するには、「シャーディングされたクラスターでのチャンクの分割」で説明されているように、コレクションを事前に分割できます。
への順序なしの書き込み mongos
シャーディングされたクラスターへの書き込みパフォーマンスを向上させるには、オプションのパラメーター ordered
を false
に設定して bulkWrite()
を使用します。mongos
は、複数のシャードへの書き込みの同時送信を試行できます。空のコレクションの場合はまず、「シャーディングされたクラスターでのチャンクの分割」で説明されているように、コレクションを事前に分割します。
単調なスロットリングを避ける
挿入中にシャードキーが単調に増加した場合、挿入されたすべてのデータはコレクションの最後のチャンクに送られ、最終的には常に 1 つのシャードになります。したがって、クラスターの挿入キャパシティーが、その 1 つのシャードの挿入キャパシティーを超えることはありません。
挿入量が単一のシャードで処理できる量よりも大きく、シャードキーの単調な増加が避けられない場合は、アプリケーションに対する次の変更を検討してください。
シャードキーのバイナリ ビットを逆にします。これによって情報が保持され、挿入の順序と値の増加順序との相関が回避されます。
インサートを「シャッフル」するには、最初と最後の 16 ビット ワードを入れ替えます。
例
C++ を使用した次の例では、生成されたBSON ObjectIdの先頭と末尾の 16 ビット ワードを入れ替えて、単調に増加しないようにします。
using namespace mongo; OID make_an_id() { OID x = OID::gen(); const unsigned char *p = x.getData(); swap( (unsigned short&) p[0], (unsigned short&) p[10] ); return x; } void foo() { // create an object BSONObj o = BSON( "_id" << make_an_id() << "x" << 3 << "name" << "jane" ); // now we may insert o into a sharded collection }