如何提高MongoDB批量性能?

时间:2015-11-21 13:23:47

标签: arrays node.js performance mongodb bulkinsert

我有一些元数据和一大堆项目。我以前将它存储在mongo中,并通过$unwind数组查询它。 但是,在极端情况下,阵列变得如此之大,以至于我遇到了16MB的BSON限制。

所以我需要将数组的每个元素存储为一个单独的文档。为此,我需要将元数据添加到所有这些,所以我可以找回它们。 It is suggested that I use bulk operations为此。

然而,表现似乎真的很慢。插入一个大文档几乎是即时的,这需要十秒

var bulk        = col.initializeOrderedBulkOp();
var metaData    = {
    hash            : hash,
    date            : timestamp,
    name            : name
};

// measure time here

for (var i = 0, l = array.length; i < l; i++) { // 6000 items
    var item = array[i];

    bulk.insert({ // Apparently, this 6000 times takes 2.9 seconds
        data        : item,
        metaData    : metaData
    });

}

bulk.execute(bulkOpts, function(err, result) { // and this takes 6.5 seconds
    // measure time here
});

批量插入6000个文档,总共38 MB的数据(在MongoDB中转换为49 MB作为BSON),性能似乎无法接受。 将元数据附加到每个文档的开销可能不是那么糟糕,对吧?更新两个索引的开销可能不好,对吗?

我错过了什么吗?是否有更好的方法来插入需要作为一组提取的文档组?

这不仅仅是我的笔记本电脑。在服务器上相同。让我觉得这不是配置错误,而是编程错误。

将MongoDB 2.6.11与节点适配器node-mongodb-native 2.0.49

一起使用

-update -

只需将元数据添加到批量帐户中的每个元素 2.9秒。需要有更好的方法来做到这一点。

1 个答案:

答案 0 :(得分:1)

批量发送批量插入操作,因为这样可以减少到服务器的流量,从而通过不在单个语句中发送所有内容来执行高效的有线事务,而是分解为服务器承诺的可管理块。使用这种方法在回调中等待响应的时间也更少。

更好的方法是使用 async 模块,因此即使循环输入列表也是非阻塞操作。选择批量大小可能会有所不同,但是选择每1000个条目的批量插入操作可以使其保持在16MB BSON硬限制之下,因为整个“请求”等于一个BSON文档。

下面演示如何使用 async 模块迭代数组并重复调用迭代器函数,而test返回true。停止时或发生错误时调用回调。

var bulk = col.initializeOrderedBulkOp(),
    counter = 0,
    len = array.length,
    buildModel = function(index){   
        return {
            "data": array[index],
            "metaData": {
                "hash": hash,
                "date": timestamp,
                "name": name
            }
        }
    };

async.whilst(
    // Iterator condition
    function() { return counter < len },

    // Do this in the iterator
    function (callback) {
        counter++;
        var model = buildModel(counter);
        bulk.insert(model);

        if (counter % 1000 == 0) {
            bulk.execute(function(err, result) {
                bulk = col.initializeOrderedBulkOp();
                callback(err);
            });
        } else {
            callback();
        }
    },

    // When all is done
    function(err) {
        if (counter % 1000 != 0) {
            bulk.execute(function(err, result) {
                console.log("More inserts.");
            }); 
        }           
        console.log("All done now!");
    }
);