Предварительное распределение записей с использованием счетчика
Я читал, что предварительное выделение записи может улучшить производительность, что должно быть особенно полезно при обработке многих записей набора данных временного ряда.
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
}
}
);
});
};
Я немного обеспокоен тем, что выполнение обещания может замедлить это, и, возможно, проверка на счетчик каждый раз сводит на нет преимущество в производительности при предварительном выделении записи.
Есть ли более эффективный способ справиться с этим?
1 ответ
Общее утверждение о "предварительном выделении" относится к потенциальной стоимости операции "обновления", которая приводит к "росту" документа. Если это приводит к тому, что размер документа больше, чем выделенное в настоящее время пространство, документ будет "перемещен" в другое место на диске для размещения нового пространства. Это может быть дорогостоящим, и, следовательно, общая рекомендация изначально написать документ, соответствующий его возможному "размеру".
Честно говоря, лучший способ справиться с такой операцией состоит в том, чтобы сначала выполнить "upsert" со всеми выделенными элементами массива, а затем только обновить требуемый элемент в позиции. Это уменьшило бы до двух возможных записей, и вы можете дополнительно сократить до одной операции "по проводам", используя методы Bulk API:
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
});
Или, поскольку более новые драйверы предпочитают согласованность друг с другом, "массовые" части были переведены в регулярные массивы 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
поскольку единственный блок будет делать что-либо только в том случае, если на самом деле происходит "упор". Основным случаем является то, что единственным контактом с сервером будет один запрос и ответ, в отличие от операций "туда-сюда", ожидающих сетевого взаимодействия.
Обычно для этого используются "массовые" операции. Они снижают нагрузку на сеть, когда вы также можете отправить пакет запросов на сервер. Результат значительно ускоряет процесс, и ни одна операция не зависит от другой, за исключением исключения "заказано", которое в последнем случае является значением по умолчанию и явно установлено устаревшим .initializeOrderedBulkOp()
,
Да, в "upsert" есть "небольшие" издержки, но есть "меньше", чем в тестировании с .count()
и ждем этого результата первым.
NB Не уверен насчет 32 записей массива в вашем списке. Возможно, вы имели в виду 24, но копирование / вставка взяли верх над вами. В любом случае, как демонстрируется, есть более эффективные способы, чем жесткое кодирование.