使用计数预分配记录
pre-allocation of records using count
我了解到记录的预分配可以提高性能,这应该是有益的,尤其是在处理时间序列数据集的许多记录时。
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
}
}
);
});
};
我有点担心必须通过承诺可能会减慢速度,并且每次都检查计数可能会抵消预分配记录的性能优势。
有没有更高效的方法来处理这个问题?
"pre-allocation" 的一般陈述是关于导致文档 "grow" 的 "update" 操作的潜在成本。如果这导致文档大小大于当前分配的 space,则文档将 "moved" 到磁盘上的另一个位置以容纳新的 space。这可能代价高昂,因此一般建议最初编写适合其最终 "size".
的文档
老实说,处理此类操作的最佳方法是先执行 "upsert" 并分配所有数组元素,然后仅更新位置所需的元素。这将减少到 "two" 潜在写入,并且您可以使用批量 API 方法进一步减少到单个 "over the wire" 操作:
var id = _ref,"|"+year+"|"+month;
var bulk = db.collection('ref_history').initializeOrderedBulkOp();
bulk.find({ "_id": id }).upsert().updateOne({
"$setOnInsert": {
"dates": Array.apply(null,Array(32)).map(function(el) { return { "count": 0 }})
}
});
var update={"$inc":inc['dates.'+day+'.count'] = 1;};
bulk.find({ "_id": id }).updateOne(update);
bulk.execute(function(err,results) {
// results would show what was modified or not
});
或者由于较新的驱动程序倾向于彼此保持一致,"Bulk" 部分已降级为 WriteOperations
的常规数组:
var update={"$inc":inc['dates.'+day+'.count'] = 1;};
db.collection('ref_history').bulkWrite([
{ "updateOne": {
"filter": { "_id": id },
"update": {
"$setOnInsert": {
"dates": Array.apply(null,Array(32)).map(function(el) {
return { "count": 0 }
})
}
},
"upsert": true
}},
{ "updateOne": {
"filter": { "_id": id },
"update": update
}}
],function(err,result) {
// same thing as above really
});
在任何一种情况下,$setOnInsert
作为唯一的块只会在 "upsert" 实际发生时才执行任何操作。主要情况是与服务器的唯一联系将是单个请求和响应,而不是 "back and forth" 等待网络通信的操作。
这通常是 "Bulk" 操作的目的。当您不妨向服务器发送一批请求时,它们会减少网络开销。结果显着加快了速度,除了 "ordered" 例外,这两个操作都不真正依赖于另一个,这是后一种情况下的默认设置,并由遗留 .initializeOrderedBulkOp()
明确设置。
是的,在 "upsert" 中有 "little" 的开销,但比使用 .count()
进行测试并先等待结果要多 "less"。
N.B 不确定您列表中的 32 个数组条目。您的意思可能是 24,但 copy/paste 占了上风。无论如何,有比硬编码更好的方法来做到这一点,正如所证明的那样。
我了解到记录的预分配可以提高性能,这应该是有益的,尤其是在处理时间序列数据集的许多记录时。
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
}
}
);
});
};
我有点担心必须通过承诺可能会减慢速度,并且每次都检查计数可能会抵消预分配记录的性能优势。
有没有更高效的方法来处理这个问题?
"pre-allocation" 的一般陈述是关于导致文档 "grow" 的 "update" 操作的潜在成本。如果这导致文档大小大于当前分配的 space,则文档将 "moved" 到磁盘上的另一个位置以容纳新的 space。这可能代价高昂,因此一般建议最初编写适合其最终 "size".
的文档老实说,处理此类操作的最佳方法是先执行 "upsert" 并分配所有数组元素,然后仅更新位置所需的元素。这将减少到 "two" 潜在写入,并且您可以使用批量 API 方法进一步减少到单个 "over the wire" 操作:
var id = _ref,"|"+year+"|"+month;
var bulk = db.collection('ref_history').initializeOrderedBulkOp();
bulk.find({ "_id": id }).upsert().updateOne({
"$setOnInsert": {
"dates": Array.apply(null,Array(32)).map(function(el) { return { "count": 0 }})
}
});
var update={"$inc":inc['dates.'+day+'.count'] = 1;};
bulk.find({ "_id": id }).updateOne(update);
bulk.execute(function(err,results) {
// results would show what was modified or not
});
或者由于较新的驱动程序倾向于彼此保持一致,"Bulk" 部分已降级为 WriteOperations
的常规数组:
var update={"$inc":inc['dates.'+day+'.count'] = 1;};
db.collection('ref_history').bulkWrite([
{ "updateOne": {
"filter": { "_id": id },
"update": {
"$setOnInsert": {
"dates": Array.apply(null,Array(32)).map(function(el) {
return { "count": 0 }
})
}
},
"upsert": true
}},
{ "updateOne": {
"filter": { "_id": id },
"update": update
}}
],function(err,result) {
// same thing as above really
});
在任何一种情况下,$setOnInsert
作为唯一的块只会在 "upsert" 实际发生时才执行任何操作。主要情况是与服务器的唯一联系将是单个请求和响应,而不是 "back and forth" 等待网络通信的操作。
这通常是 "Bulk" 操作的目的。当您不妨向服务器发送一批请求时,它们会减少网络开销。结果显着加快了速度,除了 "ordered" 例外,这两个操作都不真正依赖于另一个,这是后一种情况下的默认设置,并由遗留 .initializeOrderedBulkOp()
明确设置。
是的,在 "upsert" 中有 "little" 的开销,但比使用 .count()
进行测试并先等待结果要多 "less"。
N.B 不确定您列表中的 32 个数组条目。您的意思可能是 24,但 copy/paste 占了上风。无论如何,有比硬编码更好的方法来做到这一点,正如所证明的那样。