MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Umgang mit langsamen Abfragen in MongoDB

In der Produktion sollte eine Anwendung dem Benutzer zeitnah antworten, um die Benutzerinteraktion mit Ihrer Anwendung zu verbessern. Gelegentlich können Datenbankabfragen jedoch mit Verzögerungen beginnen, sodass eine längere Latenzzeit erforderlich ist, bis eine Antwort den Benutzer erreicht, oder vielmehr wird der Durchsatzvorgang aufgrund des Überschreitens des festgelegten durchschnittlichen Timeouts beendet.

In diesem Blog werden wir lernen, wie Sie diese Probleme in MongoDB identifizieren können, wie sie behoben werden können, wann immer sie auftreten, und welche möglichen Strategien es gibt, damit dies nicht wieder vorkommt.

P>

Häufiger führt zu langsamen Abfrageantworten eine herabgesetzte CPU-Kapazität, die dem zugrunde liegenden Arbeitssatz nicht standhalten kann. Der Arbeitssatz ist in diesem Fall die Menge an Daten und Indizes, die einer Durchsatzinstanz unterzogen werden und daher in diesem Moment aktiv sind. Dies wird insbesondere bei der Kapazitätsplanung berücksichtigt, wenn man davon ausgeht, dass die betroffene Datenmenge im Laufe der Zeit und die Anzahl der Benutzer, die sich mit Ihrer Plattform beschäftigen, zunehmen wird.

Identifizieren eines Problems mit langsamen Abfragen

Es gibt zwei Möglichkeiten, langsame Abfragen in MongoDB zu erkennen.

  1. Verwendung des Profilers
  2. Verwenden des Hilfsprogramms db.currentOp()

Verwenden des MongoDB-Profilers

Datenbank-Profiler in MongoDB ist ein Mechanismus zum Sammeln detaillierter Informationen über Datenbankbefehle, die für eine laufende Mongod-Instanz ausgeführt werden, d. h.:Durchsatzoperationen (Erstellen, Lesen, Aktualisieren und Löschen) und die Konfigurations- und Verwaltungsbefehle.

Der Profiler verwendet eine begrenzte Sammlung namens system.profile, in die er alle Daten schreibt. Das heißt, wenn die Sammlung voll ist, werden die älteren Dokumente gelöscht, um Platz für neue Daten zu schaffen.

Der Profiler ist standardmäßig ausgeschaltet, aber je nach Profiling-Level kann man ihn pro Datenbank oder pro Instanz aktivieren. Die möglichen Profilierungsebenen sind:

  • 0 - der Profiler ist ausgeschaltet und sammelt daher keine Daten.
  • 1 – Der Profiler sammelt Daten für Vorgänge, die länger dauern als der Wert von slowms
  • 2- der  Profiler sammelt Daten für alle Vorgänge.

 Die Aktivierung der Profilerstellung wirkt sich jedoch auf die Datenbank- und Festplattennutzung aus, insbesondere wenn die Profilerstellungsebene auf 2 festgelegt ist. Vor dem Aktivieren und Konfigurieren des Profilers in einer Produktionsbereitstellung sollten Sie alle Auswirkungen auf die Leistung berücksichtigen.

Um das Profiling einzustellen, verwenden wir den db.setProfilingLevel() Helfer wie:

db.setProfilingLevel(2)

Ein Beispieldokument, das in der system.profile-Sammlung gespeichert wird, ist:

{ "was" : 0, "slowms" : 100, "sampleRate" : 1.0, "ok" : 1 }

Das Schlüssel-Wert-Paar „ok“:1 zeigt an, dass die Operation erfolgreich war, während slowms die Schwellenzeit in Millisekunden ist, die eine Operation dauern sollte, und standardmäßig 100 ms beträgt.

Um diesen Wert zu ändern

db.setProfilingLevel(1, { slowms: 50 })

Um Daten aus der system.profile-Sammlung abzufragen, führen Sie Folgendes aus:

db.system.profile.find().pretty()

Verwendung von db.currentOp()helper

Diese Funktion listet die aktuell laufenden Abfragen mit sehr detaillierten Informationen auf, zB wie lange sie schon laufen. Auf einer laufenden Mongo-Shell führen Sie zum Beispiel den Kommentar aus:

db.currentOp({“secs_running”:{$gte:5}}) 

Wobei secs_running die Filterstrategie ist, sodass nur Vorgänge zurückgegeben werden, deren Ausführung mehr als 5 Sekunden gedauert hat, wodurch die Ausgabe reduziert wird. Dies wird häufig verwendet, wenn der CPU-Zustand aufgrund negativer Leistungsauswirkungen, die dies auf die Datenbank haben kann, zu 100 % bewertet werden kann. Wenn Sie also die Werte ändern, erfahren Sie, welche Abfragen lange dauern, bis sie ausgeführt werden.

Die zurückgegebenen Dokumente haben folgende interessante Schlüssel:

  • Abfrage :was die Abfrage beinhaltet
  • aktiv : wenn die Abfrage noch läuft.
  • ns :Sammlungsname, für den die Abfrage ausgeführt werden soll
  • secs_running :  Dauer der Abfrage bisher in Sekunden

Indem Sie hervorheben, welche Abfragen lange dauern, haben Sie identifiziert, was die CPU überlastet.

Ergebnisse interpretieren und Probleme beheben

 Wie wir oben beschrieben haben, hängt die Abfragelatenz stark von der Menge der betroffenen Daten ab, was andernfalls zu ineffizienten Ausführungsplänen führen würde. Das heißt, wenn Sie beispielsweise keine Indizes in Ihrer Sammlung verwenden und bestimmte Datensätze aktualisieren möchten, muss die Operation alle Dokumente durchlaufen, anstatt nur nach denen zu filtern, die der Abfragespezifikation entsprechen. Logischerweise dauert dies länger, was zu einer langsamen Abfrage führt. Sie können einen ineffizienten Ausführungsplan untersuchen, indem Sie Folgendes ausführen:  explain(‘executionStats’) , das Statistiken zur Leistung der Abfrage bereitstellt. Von diesem Punkt an können Sie erfahren, wie die Abfrage den Index verwendet, und einen Hinweis darauf geben, ob der Index optimal ist.

Wenn der Explain-Helfer zurückkehrt

{

   "queryPlanner" : {

         "plannerVersion" : 1,

         ...

         "winningPlan" : {

            "stage" : "COLLSCAN",

            ...

         }

   },

   "executionStats" : {

      "executionSuccess" : true,

      "nReturned" : 3,

      "executionTimeMillis" : 0,

      "totalKeysExamined" : 0,

      "totalDocsExamined" : 10,

      "executionStages" : {

         "stage" : "COLLSCAN",

         ...

      },

      ...

   },

   ...

}

queryPlanner.winningPlan.stage:Der COLLSCAN-Schlüsselwert gibt an, dass der Mongod das gesamte Sammlungsdokument scannen musste, um die Ergebnisse zu identifizieren, daher wird dies zu einem teuren Vorgang, der zu langsamen Abfragen führt.

executionStats.totalKeysExamined:0 bedeutet, dass die Sammlung keine Indizierungsstrategie verwendet

Für eine bestimmte Abfrage sollte die Anzahl der beteiligten Dokumente nahe Null sein. Wenn die Anzahl der Dokumente sehr groß ist, gibt es zwei Möglichkeiten:

  1. Keine Indexierung mit der Sammlung verwenden
  2. Verwenden eines Index, der nicht optimal ist.

Führen Sie den folgenden Befehl aus, um einen Index für eine Sammlung zu erstellen: 

db.collection.createIndex( { quantity: 1 } )

Wobei Menge ein Beispielfeld ist, das Sie als optimal für die Indizierungsstrategie ausgewählt haben.

Wenn Sie mehr über die Indexierung und die zu verwendende Indexierungsstrategie erfahren möchten, besuchen Sie diesen Blog

Fazit

Eine Verschlechterung der Datenbankleistung kann leicht durch langsame Abfragen dargestellt werden, was die geringste Erwartung ist, die wir von Plattformbenutzern erwarten würden. Man kann langsame Abfragen in MongoDB identifizieren, indem man den Profiler aktiviert und gemäß seinen Spezifikationen konfiguriert oder db.currentOp() auf einer laufenden Mongod-Instanz ausführt.

Indem wir uns die Zeitparameter des zurückgegebenen Ergebnisses ansehen, können wir feststellen, welche Abfragen verzögert sind. Nachdem wir diese Abfragen identifiziert haben, verwenden wir den EXPLAIN-Helfer für diese Abfragen, um weitere Details zu erhalten, beispielsweise wenn die Abfrage einen beliebigen Index verwendet.

Ohne Indizierung werden die Vorgänge teuer, da viele Dokumente gescannt werden müssen, bevor die Änderungen übernommen werden. Mit diesem Rückschlag wird die CPU überlastet, was zu langsamen Abfragen und steigenden CPU-Spitzen führt.

Der Hauptfehler, der zu langsamen Abfragen führt, ist eine ineffiziente Ausführungsplanung, die leicht behoben werden kann, indem ein Index mit der betroffenen Sammlung verwendet wird.