MongoDB Indizes verwenden

MongoDBBeginner
Jetzt üben

Einführung

In diesem Lab lernen Sie die Grundlagen der Verwendung von MongoDB-Indizes zur Optimierung der Abfrageleistung. Ein Index ist eine spezielle Datenstruktur, die einen kleinen, leicht durchsuchbaren Teil der Daten einer Collection enthält und es MongoDB ermöglicht, Dokumente wesentlich schneller zu finden, als wenn die gesamte Collection gescannt werden müsste.

Sie beginnen damit, die Leistung einer Abfrage ohne Index zu beobachten. Anschließend erstellen Sie Single-Field- und Compound-Indizes und sehen, wie diese die Abfrage- und Sortiergeschwindigkeiten dramatisch verbessern. Abschließend lernen Sie, wie Sie Ihre Indizes verwalten, indem Sie sie auflisten und entfernen. Am Ende dieses Labs werden Sie ein praktisches Verständnis dafür haben, wie Sie Indizes erstellen und verwenden, um Ihre MongoDB-Anwendungen effizienter zu gestalten.

Abfragen ohne Index

Bevor Sie einen Index erstellen, ist es wichtig zu verstehen, wie MongoDB ohne einen solchen funktioniert. In diesem Schritt richten Sie eine Beispielsammlung ein, führen eine Abfrage aus und analysieren ihren Ausführungsplan, um die Leistungsauswirkungen eines vollständigen Collection-Scans zu sehen.

Öffnen Sie zunächst die MongoDB Shell (mongosh), um mit Ihrer Datenbank zu interagieren. Diese Befehlszeilenschnittstelle ermöglicht es Ihnen, Befehle direkt gegen Ihre MongoDB-Instanz auszuführen.

mongosh

Sobald Sie sich in der Shell befinden, sehen Sie die Eingabeaufforderung >. Wechseln wir zu einer neuen Datenbank namens indexlab und fügen einige Beispieldokumente in eine users-Collection ein. Wenn die Datenbank oder Collection nicht existiert, erstellt MongoDB diese automatisch.

use indexlab
db.users.insertMany([
  { name: "Alice", age: 28, city: "New York" },
  { name: "Bob", age: 35, city: "San Francisco" },
  { name: "Charlie", age: 42, city: "Chicago" },
  { name: "David", age: 25, city: "New York" },
  { name: "Eve", age: 31, city: "San Francisco" }
]);

Nun suchen wir alle Benutzer, die älter als 30 sind. Wir verwenden die Methode .explain("executionStats"), um zu sehen, wie MongoDB diese Abfrage ausführt. Diese Methode liefert detaillierte Statistiken über den Ausführungsplan der Abfrage.

db.users.find({ age: { $gt: 30 } }).explain("executionStats");

Die Ausgabe liefert detaillierte Statistiken zur Ausführung der Abfrage. Achten Sie auf die Abschnitte winningPlan und executionStats.

Beispielausgabe (gekürzt):

{
  "queryPlanner": {
    "winningPlan": {
      "stage": "COLLSCAN",
      "filter": { "age": { "$gt": 30 } },
      "direction": "forward"
    }
  },
  "executionStats": {
    "executionSuccess": true,
    "nReturned": 3,
    "executionTimeMillis": 0,
    "totalKeysExamined": 0,
    "totalDocsExamined": 5
  }
}

Die wichtigsten Informationen hier sind stage: "COLLSCAN" und totalDocsExamined: 5.

  • COLLSCAN steht für "Collection Scan". Das bedeutet, dass MongoDB jedes einzelne Dokument in der Collection überprüfen musste, um die übereinstimmenden zu finden.
  • totalDocsExamined: 5 bestätigt, dass alle 5 Dokumente in der Collection gescannt wurden.

Obwohl dies für eine kleine Collection schnell ist, wäre ein Collection-Scan bei Millionen von Dokumenten sehr langsam. Im nächsten Schritt beheben Sie dies, indem Sie einen Index hinzufügen.

Erstellen und Verwenden eines Single-Field-Index

Nachdem Sie nun die Ineffizienz eines Collection-Scans gesehen haben, wollen wir die Leistung durch die Erstellung eines Index verbessern. Ein Index auf dem Feld age ermöglicht es MongoDB, die relevanten Dokumente schnell zu finden, ohne die gesamte Collection durchsuchen zu müssen.

Sie sollten sich immer noch in der mongosh-Shell aus dem vorherigen Schritt befinden.

Erstellen Sie einen Index auf dem Feld age in aufsteigender Reihenfolge. Die 1 gibt einen aufsteigenden Index an, während -1 einen absteigenden angeben würde.

db.users.createIndex({ age: 1 });

MongoDB wird bestätigen, dass der Index erfolgreich erstellt wurde. Der Standardname für diesen Index ist age_1.

Führen Sie nun genau dieselbe Abfrage wie im vorherigen Schritt aus und untersuchen Sie ihren Ausführungsplan.

db.users.find({ age: { $gt: 30 } }).explain("executionStats");

Beispielausgabe (gekürzt):

{
  "queryPlanner": {
    "winningPlan": {
      "stage": "FETCH",
      "inputStage": {
        "stage": "IXSCAN",
        "keyPattern": { "age": 1 },
        "indexName": "age_1"
      }
    }
  },
  "executionStats": {
    "executionSuccess": true,
    "nReturned": 3,
    "executionTimeMillis": 0,
    "totalKeysExamined": 3,
    "totalDocsExamined": 3
  }
}

Beachten Sie die signifikanten Änderungen im Ausführungsplan:

  • Die stage ist nun IXSCAN, was für "Index Scan" steht. Dies zeigt an, dass MongoDB den age_1-Index verwendet hat, um die übereinstimmenden Dokumente zu finden.
  • totalKeysExamined und totalDocsExamined sind nun 3 statt 5. MongoDB musste nur die 3 Dokumente betrachten, die über den Index mit der Abfrage übereinstimmten, und die anderen 2 ignorieren. Dies ist die Quelle des Leistungszuwachses.

Verwenden eines zusammengesetzten Index für die Sortierung

Indizes dienen nicht nur zur Beschleunigung von Abfragen, sondern sind auch entscheidend für effizientes Sortieren. Wenn Sie nach einem Feld sortieren, das nicht indiziert ist, muss MongoDB die Sortierung im Speicher durchführen, was langsam sein und erheblichen RAM verbrauchen kann. Ein Compound-Index, der mehrere Felder umfasst, kann Abfragen optimieren, die diese Felder filtern und sortieren.

Erstellen wir einen Compound-Index auf den Feldern city (aufsteigend) und age (absteigend). Die Reihenfolge der Felder im Index ist wichtig für seine Verwendung.

db.users.createIndex({ city: 1, age: -1 });

Führen wir nun eine Abfrage aus, die die Benutzer nach Stadt und dann nach Alter sortiert. Wir verwenden erneut .explain(), um zu bestätigen, dass der Index für die Sortierung verwendet wird.

db.users.find().sort({ city: 1, age: -1 }).explain("executionStats");

Beispielausgabe (gekürzt):

{
  "queryPlanner": {
    "winningPlan": {
      "stage": "FETCH",
      "inputStage": {
        "stage": "IXSCAN",
        "keyPattern": { "city": 1, "age": -1 },
        "indexName": "city_1_age_-1"
      }
    }
  }
}

Die IXSCAN-Phase zeigt, dass MongoDB unseren neuen city_1_age_-1-Index verwendet hat. Da die Daten im Index bereits gemäß unseren Sortierkriterien geordnet sind, muss MongoDB keinen separaten, kostspieligen Sortierschritt im Speicher durchführen.

Um das tatsächlich sortierte Ergebnis zu sehen, führen Sie die Abfrage ohne .explain() aus.

db.users.find().sort({ city: 1, age: -1 });

Ausgabe:

[
  { _id: ObjectId("..."), name: 'Charlie', age: 42, city: 'Chicago' },
  { _id: ObjectId("..."), name: 'Alice', age: 28, city: 'New York' },
  { _id: ObjectId("..."), name: 'David', age: 25, city: 'New York' },
  { _id: ObjectId("..."), name: 'Bob', age: 35, city: 'San Francisco' },
  { _id: ObjectId("..."), name: 'Eve', age: 31, city: 'San Francisco' }
]

Die Dokumente sind korrekt sortiert, zuerst nach city alphabetisch und dann nach age vom ältesten zum jüngsten innerhalb jeder Stadt, entsprechend der Definition des Compound-Index.

Verwalten und Entfernen von Indizes

Obwohl Indizes die Leseleistung verbessern, sind sie nicht kostenlos. Sie verbrauchen Speicherplatz und fügen Schreiboperationen (Einfügungen, Aktualisierungen und Löschungen) einen geringen Overhead hinzu. Daher ist es eine gute Praxis, nicht mehr verwendete Indizes regelmäßig zu überprüfen und zu entfernen.

Zuerst können Sie alle Indizes einer Collection mit der Methode getIndexes() auflisten.

db.users.getIndexes();

Ausgabe:

[
  { "v": 2, "key": { "_id": 1 }, "name": "_id_" },
  { "v": 2, "key": { "age": 1 }, "name": "age_1" },
  { "v": 2, "key": { "city": 1, "age": -1 }, "name": "city_1_age_-1" }
]

Dies zeigt den Standardindex auf dem Feld _id, der automatisch für jede Collection erstellt wird, sowie die beiden von uns erstellten Indizes.

Nehmen wir an, wir haben festgestellt, dass der Compound-Index city_1_age_-1 nicht mehr benötigt wird. Sie können ihn mit der Methode dropIndex() entfernen, indem Sie den Indexnamen als Argument übergeben.

db.users.dropIndex("city_1_age_-1");

MongoDB gibt ein Objekt zurück, das angibt, wie viele Indizes vor der Löschoperation vorhanden waren.

{ "nIndexesWas": 3, "ok": 1 }

Überprüfen Sie nun, ob der Index entfernt wurde, indem Sie die Indizes erneut auflisten.

db.users.getIndexes();

Ausgabe:

[
  { "v": 2, "key": { "_id": 1 }, "name": "_id_" },
  { "v": 2, "key": { "age": 1 }, "name": "age_1" }
]

Wie Sie sehen können, ist der Index city_1_age_-1 verschwunden. Eine ordnungsgemäße Indexverwaltung ist ein wichtiger Bestandteil der Aufrechterhaltung einer gesunden und performanten Datenbank.

Um die MongoDB-Shell zu beenden, können Sie exit eingeben oder Strg+D drücken.

exit;

Zusammenfassung

In diesem Lab haben Sie die wesentlichen Techniken für die Verwendung von MongoDB-Indizes kennengelernt. Sie haben damit begonnen, einen COLLSCAN bei einer Abfrage ohne Index zu beobachten und dessen Leistungseinschränkungen verstanden. Anschließend haben Sie einen Single-Field-Index erstellt, der den Abfrageplan zu einem wesentlich effizienteren IXSCAN geändert hat.

Darüber hinaus haben Sie Compound-Indizes untersucht und gesehen, wie sie zur Optimierung von Sortieroperationen verwendet werden können, um kostspielige In-Memory-Sortierungen zu vermeiden. Schließlich haben Sie gelernt, wie Sie Ihre Indizes verwalten, indem Sie sie mit getIndexes() auflisten und nicht verwendete mit dropIndex() entfernen. Diese Fähigkeiten sind grundlegend für die Entwicklung schneller und skalierbarer Anwendungen mit MongoDB.