MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Как да увеличим производителността на операцията за актуализиране в Mongo?

Когато актуализирате по начина, по който сте, трябва да извлечете съдържанието на документа, за да го прегледате и да направите такива модификации. MongoDB няма атомарни операции, които действат върху съществуващите стойности по начина, по който искате да направите, така че разбира се е необходимо повторение.

Няма реална разлика в частта "заявка" за това как съпоставяте регулярния израз между двете ви версии на изявлението. Без значение какво, съдържанието се преобразува в BSON, преди да бъде изпратено до сървъра, така че ако използвате стандартен конструктор на изрази или директен BSON документ, няма никакво значение.

Но към подобренията в производителността, които могат да бъдат направени.

Използвайте групови операции за актуализиране

Както беше посочено, груповите операции са начинът, по който трябва да актуализирате такава итерация на списък и също така „трябва“ да използвате курсор, вместо да преобразувате всички резултати в списък, тъй като това ще спести памет.

Избягване на всички специфични декларации за тип и просто представяне като BsonDocument (което вероятно ще ви спести маршалиране, но не е необходимо), тогава основният примерен процес би бил:

var pattern = @"(?si)<([^\s<]*workUnit[^\s<]*)>.*?</\1>";
var filter = Builders<JobInfoRecord>.Filter.Regex(x => x.SerializedBackgroundJobInfo,
                                              new BsonRegularExpression(pattern, "i"));


var ops = new List<WriteModel<BsonDocument>>();
var writeOptions = new BulkWriteOptions() { IsOrdered = false };

using ( var cursor = await records.FindAsync<BsonDocument>(filter))
{
    while ( await cursor.MoveNextAsync())
    {
        foreach( var doc in cursor.Current )
        {
            // Replace inspected value
            var updatedJobInfo = Regex.Replace(doc.SerializedBackgroundJobInfo, pattern, "<$1></$1>");

            // Add WriteModel to list
            ops.Add(
                new UpdateOneModel<BsonDocument>(
                    Builders<BsonDocument>.Filter.Eq("JobTypeValue", doc.JobTypeValue),
                    Builders<BsonDocument>.Update.Set("SerializedBackgroundJobInfo", updatedJobInfo)
                )
            );

            // Execute once in every 1000 and clear list
            if (ops.Count == 1000)
            {
                BulkWriteResult<BsonDocument> result = await records.BulkWriteAsync(ops,writeOptions);
                ops = new List<WriteModel<BsonDocument>>();
            }
        }
    }

    // Clear any remaining
    if (ops.Count > 0 )
    {
        BulkWriteResult<BsonDocument> result = await records.BulkWriteAsync(ops,writeOptions);
    }

}

Така че вместо да правите заявка към базата данни за всеки един документ, извлечен от заявката, вие създавате List на WriteModel вместо това.

След като този списък нарасне до разумна стойност (1000 в този пример), вие извършвате операцията за запис към сървъра с една заявка и отговор за всички пакетни операции. Тук използваме BulkWriteAsync .

Можете да създавате партиди в размер, по-голям от 1000, ако желаете, но обикновено това е разумен брой, с който да се справите. Единственото реално твърдо ограничение е ограничението на BSON от 16MB, което тъй като всички заявки все още са всъщност BSON документи, това все още важи. Така или иначе са необходими много заявки, за да се доближи до 16MB, но има и съвпадение на импеданса, за да се вземе предвид как заявката ще бъде обработена, когато действително достигне до сървъра, както е документирано:

"Всяка група от операции може да има най-много 1000 операции. Ако група надвиши това ограничение, MongoDB ще раздели групата на по-малки групи от 1000 или по-малко. Например, ако списъкът с групови операции се състои от 2000 операции за вмъкване, MongoDB създава 2 групи, всяка с 1000 операции."

Следователно, като поддържате размера на заявката на същото ниво на начина, по който сървърът ще я обработи, вие също получавате полза от yield където „множество партиди“ всъщност могат да действат в паралелни връзки към сървъра, вместо да оставят сървъра да извършва разделянето и опашката.

Върнатият резултат е BulkWriteResult който ще съдържа информация за броя на „съвпаденията“ и „модификациите“ и т.н. от пакета изпратени операции.

Естествено, тъй като операциите са в „партиди“, има смисъл след това да проверите в края на итерацията на цикъла, за да видите дали има още „партидни“ операции в списъка, и след това, разбира се, да подадете по същия начин.

Също така отбелязваме IsOrdered = false като BulkWriteOptions означава, че партидата от операции всъщност не се изпълнява в сериен ред, което означава, че сървърът всъщност може да изпълнява таксите "паралелно". Това може да доведе до "огромни" подобрения на скоростта, когато не се изисква ред на ангажиране. По подразбиране се изпраща "поръчано" и последователно.

Това не е необходимо, за да зададете тази опция, но ако поръчката ви не е важна (което не би трябвало да е в този случай, тъй като тук никакви други заявки за операция не зависят от предишната модификация на документ), тогава подобрението, което получавате, си заслужава.

Това е "намаляване" на броя на действителните заявки, направени към сървъра. Изпращането на актуализации и чакането на отговор отнема време, а при големи операции е много скъпо упражнение. Това е, с което трябва да се справят груповите операции, като се прилагат няколко операции в рамките на една заявка.

Намаляването на тези режийни разходи е "огромно" увеличение на производителността. Ето защо използвате това.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Как мога да запиша няколко документа едновременно в Mongoose/Node.js?

  2. използвайки низ за mongodb _id

  3. Кога да използвате CouchDB над MongoDB и обратно

  4. MongoDB ИЗБЕРЕТЕ БРОЙ ГРУПА ОТ

  5. Mongodb масив $push и $pull