Bulk Method とは
2.6から実装された、大量にinsert、updateを行うときに
効率よく処理してくれる便利な物
実装以前
db.table_name.insert([{docA}, {docB}, {docC}])
こんな感じで配列で渡してあげることで実現してた
使って見る
var bulk = db.tbl_name.initializeUnorderedBulkOp();
bulk.insert ({docA});
bulk.insert ({docB});
bulk.insert ({docC});
bulk.execute();
まず、bulkオブジェクトを生成しその後に実行したい操作をつんでいく
最後にexecuteメソッドを利用して反映。
bulkオブジェクトには、 initializeUnorderedBulkOp と initializeOrderedBulkOp が存在する。
UnorderedとOrederd
エラー発生時にそのまま続けるかどうか
main.js
var try_bulk_insert = function(bulk) {
bulk.find({}).remove();
bulk.insert(datas[5000]);
datas.forEach(function(i) { bulk.insert (i) });
try {
bulk.execute();
} catch (e) {
printjson(e);
}
}
try_bulk_insert(
db.tbl_insert_unorderd_bulk.initializeUnorderedBulkOp()
);
try_bulk_insert(
db.tbl_insert_orderd_bulk.initializeOrderedBulkOp()
);
結果
Orederdはエラー発生で処理を中断しているが
Unorderedは可能な限り実行している
{
"writeErrors" : [
{
"index" : 5002,
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: test.tbl_insert_unorderd_bulk index: _id_ dup key: { : ObjectId('xxxxx') }",
"op" : {
"_id" : ObjectId("xxxxx"),
"skey" : 89,
"user_id" : 1752659,
"area_id" : 3,
"comp" : 2,
"map_id" : 1
}
}
],
"writeConcernErrors" : [ ],
"nInserted" : 100000,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
}
{
"writeErrors" : [
{
"index" : 5002,
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: test.tbl_insert_orderd_bulk index: _id_ dup key: { : ObjectId('xxxxx') }",
"op" : {
"_id" : ObjectId("xxxxx"),
"skey" : 89,
"user_id" : 1752659,
"area_id" : 3,
"comp" : 2,
"map_id" : 1
}
}
],
"writeConcernErrors" : [ ],
"nInserted" : 5001,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
}
計測する
main.js
//
// 10万件のデータ,以下の形式のファイルを読み込み
// var datas = [ { object }, {object} ];
//
load("./tbl_data.json");
var measure = function(tag, target_func)
{
var startTime = new Date();
target_func();
var endTime = new Date();
print(tag + " : " + (endTime - startTime) + "ms");
};
// 一件ずつinsert
measure("insert 1", function() {
datas.forEach(function(i) {db.tbl_insert.insert (i) });
});
// 1000件ずつ配列によるBulkinsert
measure("insert 2", function() {
for (var i = 0; i < datas.length; i += 1000) {
db.tbl_insert_bulk.insert( datas.slice(i, i + 1000) );
}
});
// BulkMethodを利用したinsert
measure("insert 3", function() {
var bulk = db.tbl_bulk.initializeUnorderedBulkOp();
datas.forEach(function(i) { bulk.insert (i) });
bulk.execute();
});
実行結果
$ mongo main.js
MongoDB shell version: 3.0.5
connecting to: test
insert 1 : 53365ms
insert 2 : 5903ms
insert 3 : 6138ms
結果
バッチ処理で今回のような大量にinsertすることがあると思う。
こういうときは BulkInsert を利用する。
数十件レベルであれば、配列によるBulkInsertで問題ない
数千件を超えてくる場合であればBulkMethodを使うほうが
自分でスライスしたり調整しなくていいので楽かなと