Javascript 使用计数预分配记录

Javascript 使用计数预分配记录,javascript,node.js,mongodb,mongodb-query,pre-allocation,Javascript,Node.js,Mongodb,Mongodb Query,Pre Allocation,我已经读到,预先分配一条记录可以提高性能,这应该是有益的,特别是在处理一个时间序列数据集的许多记录时 updateRefLog = function(_ref,year,month,day){ var id = _ref,"|"+year+"|"+month; db.collection('ref_history').count({"_id":id},function(err,count){ // pre-allocate if needed if

我已经读到,预先分配一条记录可以提高性能,这应该是有益的,特别是在处理一个时间序列数据集的许多记录时

updateRefLog = function(_ref,year,month,day){
    var id = _ref,"|"+year+"|"+month;
    db.collection('ref_history').count({"_id":id},function(err,count){
        // pre-allocate if needed
        if(count < 1){
            db.collection('ref_history').insert({
                "_id":id
                ,"dates":[{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0},{"count":0}]
            });
        }

        // update
        var update={"$inc":inc['dates.'+day+'.count'] = 1;};
        db.collection('ref_history').update({"_id":id},update,{upsert: true},
            function(err, res){
                if(err !== null){
                    //handle error
                }
            }
        );
    });
};
updaterelog=函数(_ref,年,月,日){
变量id=_ref,“|”+年+“|”+月;
db.collection('ref_history').count({“_id”:id},函数(err,count){
//如果需要,预先分配
如果(计数<1){
数据库集合(“参考历史”)。插入({
“_id”:id
“日期”的“日期”的“日期”的“日期”的“日期”的“日期”的“日期”的“日期”的“日期”的“日期”的“日期”的“日期”的“日期”的“日期”的“日期”的“{“计数”的计数:0 0 0 0},,{“计数”的0 0},,,,,{“计数”的纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约的金属金属金属金属金属金属金属金属金属的纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约纽约“计数”:0},{“计数”:0},{“计数”:0},{“计数”:0},{“计数”:0},{“计数”:0}{“计数”:0},{“计数”:0},{“计数”:0},{“计数”:0},{“计数”:0}]
});
}
//更新
var update={“$inc”:inc['dates.+day+'.count']=1;};
db.collection('ref_history').update({“_id”:id},update,{upsert:true},
函数(err、res){
如果(错误!==null){
//处理错误
}
}
);
});
};
我有点担心,必须履行承诺可能会减慢速度,并且每次检查计数可能会否定预分配记录的性能优势

是否有更有效的方法来处理此问题?

关于“预分配”的一般说明是关于导致文档“增长”的“更新”操作的潜在成本。如果这导致文档大小大于当前分配的空间,则文档将被“移动”“到磁盘上的另一个位置以容纳新空间。这可能代价高昂,因此一般建议首先编写适合其最终“大小”的文档

老实说,处理这样一个操作的最佳方法是,首先在分配所有数组元素的情况下执行“upsert”,然后只更新所需元素的位置。这将减少到“两次”潜在写入,并且您可以使用批量API方法进一步减少到单个“在线”操作:

var id=_ref,“|”+年+“|”+月;
var bulk=db.collection('ref_history')。initializeOrderedBulkOp();
bulk.find({“\u id”:id}).upsert().updateOne({
“$setOnInsert”:{
“dates”:Array.apply(null,Array(32)).map(函数(el){return{“count”:0})
}
});
var update={“$inc”:inc['dates.+day+'.count']=1;};
bulk.find({“\u id”:id}).updateOne(update);
bulk.execute(函数(错误、结果){
//结果将显示修改或不修改的内容
});
或者,由于较新的驱动程序倾向于彼此之间的一致性,“批量”部分已降级为
WriteOperations
的常规数组:

var update={“$inc”:inc['dates.+day+'.count']=1;};
db.集合('ref_history')。批量写入([
{“updateOne”:{
“筛选器”:{“_id”:id},
“更新”:{
“$setOnInsert”:{
“日期”:数组.apply(null,数组(32)).map(函数(el){
返回{“计数”:0}
})
}
},
“向上插入”:正确
}},
{“updateOne”:{
“筛选器”:{“_id”:id},
“更新”:更新
}}
],函数(错误,结果){
//真的和上面一样
});
在这两种情况下,作为唯一块的as仅在实际发生“向上插入”时才会执行任何操作。主要情况是,与服务器的唯一联系将是单个请求和响应,而不是等待网络通信的“来回”操作

这通常是“批量”操作的目的。当您还可以向服务器发送一批请求时,它们可以减少网络开销。结果大大加快了速度,除了“ordered”异常(后一种情况下的默认值)之外,两个操作都不真正依赖于另一个操作,并且由遗留的
显式设置。initializeOrderedBulkOp()

是的,“upsert”中有“少量”开销,但与使用
.count()
并首先等待结果的测试相比,开销“较少”



注意:不确定列表中的32个数组项。你的意思可能是24岁,但复制/粘贴占了上风。无论如何,有比硬编码更好的方法来实现这一点,正如所演示的。

我的意思是31个条目(月内的最大天数),但我将其切换到一个以日期为键的对象,而不是数组,这样我可以从1开始,而不是从0开始。@Daniel这也是有效的,但当然,除非您再次“预分配”这样,空间就有可能再次移动文档。无论实际的最终实现是什么,最好的做法是“upsert”,而不是等待计数返回。这是你的问题,因此答案是这样的。即使您决定只尝试一次完整写入,并且在之后删除了所有键/数组项,您仍然需要决定以某种方式写入新文档。每次升级都会超过
.find()
,然后是
.insert()
。我发现在我的测试中,最快的方法是根本不预分配,而find方法的性能似乎比批量插入的性能好得多。很可能是我的设置造成了这种情况,但我暂时将推迟性能调整。@Daniel这很容易主观,并不是真正测试所有情况。的确,“并非所有增长”都会导致文档被移动,这是发生这种情况时的主要成本。因此,如果您的文档从未超出初始默认分配,那么就不必添加所有密钥。但它仍然不能改变这样一个事实,即您需要在某个时候创建一个新文档,除非您确定您总是要创建一个新文档