MongoDB CRUD操作:批量寫操作
文章目錄
- MongoDB CRUD操作:批量寫操作
- 關于批量操作的順序
- bulkWrite()支持的方法
- 舉例
- 向分片集合批量插入的策略
- 預分割集合
- 無序寫入 mongos
- 避免單調節流
MongoDB提供了批量執行寫入操作的能力,但批量寫入操作只影響單個集合, MongoDB允許應用程序確定批量寫入操作所需的可接受的確認級別。
db.collection.bulkWrite()
方法支持批量插入、更新和刪除的操作。當然,通過
db.collection.insertMany()
方法也可以進行批量插入的操作。
關于批量操作的順序
批量寫入操作可以是有序的,也可以是無序的。通過操作的有序列表,MongoDB串行執行操作。如果在處理其中一個寫操作期間發生錯誤,MongoDB 將返回,而不處理列表中任何剩余的寫操作。
對于無序列表的操作,MongoDB可以并行執行操作,但不能保證這種行為。如果在處理其中一個寫操作的過程中發生錯誤,MongoDB將繼續處理列表中剩余的寫操作。
在分片集合上執行有序操作列表通常會比執行無序列表慢,因為使用有序列表時,每個操作都必須等待前一個操作完成。
默認情況下,bulkWrite()
執行有序操作,如果要指定無序寫入操作,可以選項文檔中設置ordered: false
。
bulkWrite()支持的方法
bulkWrite()
支持下面的寫操作:
insertOne
updateOne
updateMany
replaceOne
deleteOne
deleteMany
所有的寫操作都作為數組中的文檔傳遞給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
添加兩個文檔 - 使用
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: {}
}
向分片集合批量插入的策略
大量插入操作(包括初始數據插入或常規數據導入)可能會影響分片集群的性能。對于批量插入,可考慮以下策略:
預分割集合
如果分片集合為空,則該集合只有一個初始塊,該塊駐留在單個分片上,MongoDB必須花時間接收數據、創建拆分并將拆分塊分發到可用分片。為了避免這種性能成本,可以預先拆分集合。
無序寫入 mongos
要提高分片集群的寫入性能,可以使用bulkWrite()``,并將可選參數ordered
設置為false
。 mongos可以嘗試同時將寫入發送到多個分片。對于空集合,首先按照分片集群中的分割塊中的描述預先分割集合。
避免單調節流
如果分片鍵在插入期間單調增加,則所有插入的數據都會到達集合中的最后一個塊,該塊將始終位于單個分片上。因此,集群的插入容量永遠不會超過單個分片的插入容量。
如果插入量大于單個分片可以處理的量,并且無法避免單調遞增的分片鍵,則建議對應用程序進行以下修改:
- 反轉片鍵的二進制位。這保留了信息并避免將插入順序與遞增的值序列相關聯。
- 交換第一個和最后一個 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() {// 創建一個對象BSONObj o = BSON( "_id" << make_an_id() << "x" << 3 << "name" << "jane" );
}