2016-03-02 3 views
3

Я читал, что предварительное выделение записи может улучшить производительность, что должно быть полезно, особенно при обработке многих записей набора временных рядов.предварительное распределение записей с использованием счета

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 
       } 
      } 
     ); 
    }); 
}; 

Я немного обеспокоен тем, что, чтобы пройти через обещание может замедлить это вниз, и, возможно, проверка счетчика каждый раз, когда бы свести на нет преимущества в производительности предварительного выделения записи.

Есть ли более эффективный способ справиться с этим?

+0

Какая версия MongoDB вы используете .. и если MongoDB 3.0 или более новый, какой механизм хранения? Preallocation - это полезный метод оптимизации для механизма хранения MMAP, но добавляет накладные расходы для других систем хранения (например, WiredTiger), которые не поддерживают обновления на месте. – Stennie

ответ

1

Общая информация о «предварительном распределении» относится к потенциальной стоимости операции «обновления», которая заставляет документ «расти». Если это приведет к размеру документа, который больше, чем текущее выделенное пространство, тогда документ будет «перемещен» в другое место на диске, чтобы разместить новое пространство. Это может быть дорогостоящим и, следовательно, общей рекомендацией, чтобы написать документ, подходящий для его возможного «размера».

Честно говоря, лучшим способом справиться с такой операцией было бы выполнить «upsert» изначально со всеми выделенными элементами массива, а затем только обновить элемент requried в позиции. Это позволит сократить до «два» потенциальных пишет, и вы можете дополнительно уменьшить до одного «по проводам» операция с использованием массовых методов 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 
}); 

или после новых водителей в пользу согласованности друг с другом, то «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“на самом деле происходит. Основной случай заключается в том, что единственным контактом с сервером будет один запрос и ответ, в отличие от операций «назад и вперед», ожидающих сетевой связи.

Обычно это операции «Массовые». Они уменьшают накладные расходы в сети, если вы также можете отправить пакет запросов на сервер. Результат значительно ускоряет работу, и ни одна операция не зависит от другой, за исключением «упорядоченной», которая по умолчанию используется в последнем случае и явно задана устаревшим .initializeOrderedBulkOp().

Да, в «upsert» есть «небольшие» накладные расходы, но есть «меньше», чем при тестировании .count() и в ожидании этого результата.


N.B Не уверен, что в 32 строках массива в вашем списке. Возможно, вы имели в виду 24, но копирование/вставка стали лучше вас. Во всяком случае, есть лучшие способы сделать это, чем hardcoding, как показано.

+0

Я имел в виду, что это 31 запись (для максимальных дней в месяце), но я переключу его на объект с датами как на клавиши вместо массива, таким образом я могу начать с 1 вместо 0. – Daniel

+0

@ Daniel Какой также верно, но, разумеется, если вы снова не «предварительно распределите» пространство, тогда есть потенциал для того, чтобы документ снова перемещался. Какова бы ни была ваша фактическая конечная реализация, тогда лучше всего сделать это «upsert», а не ждать возврата от счета. Это был ваш вопрос, и поэтому в этом и заключается ответ.Даже если вы решили только выполнить полную запись ** один раз **, и даже если вы удалили все ключи/записи массива впоследствии, вам все равно нужно решить каким-то образом написать новый документ. Upserts trump '.find()' then '.insert()' каждый раз. –

+0

Я нахожу, что в моих тестах наиболее быстрым является не предварительное выделение, а метод find, по-видимому, превосходит объемную вставку с небольшим отрывом. Вполне вероятно, что что-то с моей настройкой вызвало это, но пока я не буду выполнять настройку производительности. – Daniel

Смежные вопросы