sql >> Database teknologi >  >> NoSQL >> MongoDB

Hvordan øger man ydeevnen af ​​opdateringsoperationen i Mongo?

Når du opdaterer på den måde, du er, skal du hente dokumentindholdet for at kunne inspicere det og foretage sådanne ændringer. MongoDB har ingen atomoperationer, der virker på eksisterende værdier på den måde, du ønsker at gøre, så iteration er selvfølgelig påkrævet.

Der er ingen reel forskel i "forespørgslen"-delen af, hvordan du matcher det regulære udtryk mellem dine to versioner af sætningen. Uanset hvad, bliver indholdet alligevel konverteret til BSON, inden det sendes til serveren, så hvis du bruger en standardudtryksbygger eller et direkte BSON-dokument, har det ingen betydning.

Men videre til de præstationsforbedringer, der kan foretages.

Brug Bulk Operations til at opdatere

Som nævnt er Bulk Operations måden, du skal opdatere på en sådan listeiteration, og du "bør" også bruge en markør i stedet for at konvertere alle resultater til en liste, da det vil spare på hukommelsen.

Undgå alle de specifikke typeerklæringer og repræsenterer blot som BsonDocument (hvilket sandsynligvis vil spare dig for rangering, men ikke nødvendigt), så ville den grundlæggende eksempelproces være:

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

}

Så i stedet for at lave en anmodning til databasen for hvert enkelt dokument, der hentes fra forespørgslen, opretter du en List af WriteModel operationer i stedet.

Når først denne liste er vokset til en rimelig værdi (1000 i dette eksempel), forpligter du skriveoperationen til serveren i en enkelt anmodning og svar for alle batchoperationer. Her bruger vi BulkWriteAsync .

Du kan oprette batches i en størrelse større end 1000, hvis du vil, men det er generelt et rimeligt antal at håndtere. Den eneste rigtige hårde grænse er BSON-grænsen på 16MB, som da alle anmodninger stadig er BSON-dokumenter, gælder dette stadig. Det kræver i hvert fald mange anmodninger at nærme sig 16 MB, men der er også et impedensmatch at overveje i, hvordan anmodningen vil blive behandlet, når den rent faktisk når serveren, som dokumenteret:

"Hver gruppe af operationer kan højst have 1000 operationer. Hvis en gruppe overskrider denne grænse, vil MongoDB opdele gruppen i mindre grupper på 1000 eller derunder. For eksempel, hvis bulk operationslisten består af 2000 indsættelsesoperationer, MongoDB opretter 2 grupper, hver med 1000 operationer."

Derfor får du også fordelen ved yield ved at holde forespørgselsstørrelsen på samme niveau som, hvordan serveren vil behandle den. hvor "flere batches" i virkeligheden kan fungere i parallelle forbindelser til serveren i stedet for at lade serveren opdele og stå i kø.

Det returnerede resultat er BulkWriteResult som vil indeholde oplysninger om antallet af "matches" og "modifikationer" osv. fra den batch af operationer, der er sendt.

Da operationerne er i "batches", giver det naturligvis mening at tjekke i slutningen af ​​loop-iterationen for at se, om der findes flere "batchede" operationer på listen, og så selvfølgelig indsende på samme måde.

Bemærk også IsOrdered = false som BulkWriteOptions betyder, at batchen af ​​operationer faktisk ikke udføres i seriel rækkefølge, hvilket betyder, at serveren faktisk kan køre taks "parallelt". Dette kan give "store" hastighedsforbedringer, hvor rækkefølgen af ​​engagement ikke er påkrævet. Standarden er at indsende "bestilt" og serielt.

Dette er ikke påkrævet for at indstille denne mulighed, men hvis din ordre ikke er vigtig (hvilket den ikke burde være i dette tilfælde, da ingen andre handlingsanmodninger her afhænger af den tidligere ændring af et dokument), så er den forbedring, du får, umagen værd.

Det, det hele handler om, er at "reducere" antallet af faktiske anmodninger til serveren. At sende opdateringer og afvente svar tager tid, og i store operationer er det en meget bekostelig øvelse. Det er det, Bulk Operations skal håndtere ved at anvende flere operationer inden for den ene anmodning.

At reducere denne overhead er en "stor" præstationsgevinst. Det er derfor, du bruger dette.




  1. 3 måder at sortere dokumenter i MongoDB

  2. Flask-Mail og Redis Queue biblioteksintegration giver fejl

  3. MongoDB $mul

  4. Redis indsættelse ude af drift, eller sorterer mærkeligt?