Verwalten der Indizierung in der Azure Cosmos DB-API für MongoDB

GILT FÜR: Azure Cosmos DB-API für MongoDB

Die Azure Cosmos DB-API für MongoDB nutzt die Kernfunktionen für automatische Indexverwaltung von Azure Cosmos DB. Dieser Artikel konzentriert sich auf das Hinzufügen von Indizes mithilfe der Azure Cosmos DB-API für MongoDB. Indizes sind spezialisierte Datenstrukturen, die das Abfragen Ihrer Daten um etwa eine Größenordnung beschleunigen.

Indizierung für MongoDB-Serverversion 3.6 und höher

Azure Cosmos DB-API für MongoDB Server Version 3.6 und höher indiziert automatisch das Feld _id und den Shard-Schlüssel (nur in Shard-Sammlungen). Die API erzwingt automatisch die Eindeutigkeit des Felds _id durch einen Shardschlüssel.

Die API für MongoDB verhält sich anders als die Azure Cosmos DB-SQL-API, die standardmäßig alle Felder indiziert.

Bearbeiten der Indizierungsrichtlinie

Es wird empfohlen, die Indizierungsrichtlinie im Azure-Portal im Daten-Explorer zu bearbeiten. Über den Editor für Indizierungsrichtlinien im Daten-Explorer können Sie Einzelfeldindizes und Indizes mit Platzhalterzeichen hinzufügen:

Editor für Indizierungsrichtlinien

Hinweis

Mit dem Editor für Indizierungsrichtlinien im Daten-Explorer können Sie keine zusammengesetzten Indizes erstellen.

Indextypen

Einzelfeld

Sie können für jedes einzelne Feld Indizes erstellen. Die Sortierreihenfolge des Einzelfeldindexes ist unerheblich. Der folgende Befehl erstellt einen Index für das Feld name:

db.coll.createIndex({name:1})

Sie können denselben Einzelfeldindex für name im Azure-Portal erstellen:

Hinzufügen eines Namensindex im Editor für Indizierungsrichtlinien

Bei einer Abfrage werden mehrere Einzelfeldindizes verwendet, soweit verfügbar. Sie können pro Container bis zu 500 Einzelfeldindizes erstellen.

Zusammengesetzte Indizes (MongoDB-Serverversion 3.6 und höher)

In der API für MongoDB sind zusammengesetzte Indizes erforderlich, wenn Ihre Abfrage mehrere Felder gleichzeitig sortieren kann. Für Abfragen mit mehreren Filtern, die nicht sortiert werden müssen, sollten Sie anstelle eines einzelnen zusammengesetzten Indexes mehrere Einzelfeldindizes erstellen.

Ein zusammengesetzter Index oder ein einzelner Feldindex für jedes Feld im zusammengesetzten Index führt zu der gleichen Leistung beim Filtern in Abfragen.

Hinweis

Für geschachtelte Eigenschaften oder Arrays können Sie keine zusammengesetzten Indizes erstellen.

Der folgende Befehl erstellt einen zusammengesetzten Index für die Felder name und age:

db.coll.createIndex({name:1,age:1})

Sie können zusammengesetzte Indizes zum gleichzeitigen Sortieren anhand mehrerer Felder verwenden, wie im folgenden Beispiel gezeigt:

db.coll.find().sort({name:1,age:1})

Sie können obigen zusammengesetzten Index auch für die effiziente Sortierung einer Abfrage mit der umgekehrten Sortierreihenfolge anhand aller Felder verwenden. Hier sehen Sie ein Beispiel:

db.coll.find().sort({name:-1,age:-1})

Allerdings muss die Reihenfolge der Pfade im zusammengesetzten Index exakt mit der Abfrage übereinstimmen. Hier sehen Sie ein Beispiel für eine Abfrage, die einen zusätzlichen zusammengesetzten Index erfordern würde:

db.coll.find().sort({age:1,name:1})

Hinweis

Zusammengesetzte Indizes werden nur in Abfragen verwendet, mit denen Ergebnisse sortiert werden. Für Abfragen mit mehreren Filtern, die nicht sortiert werden müssen, sollten Sie mehrere Einzelfeldindizes erstellen.

Indizes mit mehreren Schlüsseln

Azure Cosmos DB erstellt Indizes mit mehreren Schlüsseln, um in Arrays gespeicherte Inhalte zu indizieren. Wenn Sie ein Feld mit einem Arraywert indizieren, indiziert Azure Cosmos DB automatisch alle Elemente im Array.

Räumliche Indizes

Viele räumliche Operatoren profitieren von räumlichen Indizes. Derzeit unterstützt die Azure Cosmos DB-API für MongoDB 2dsphere-Indizes. Die API unterstützt 2d-Indizes noch nicht.

Hier sehen Sie ein Beispiel für das Erstellen eines räumlichen Indexes für das Feld location:

db.coll.createIndex({ location : "2dsphere" })

Textindizes

Derzeit unterstützt die Azure Cosmos DB-API für MongoDB Textindizes noch nicht. Bei Textsuchabfragen für Zeichenfolgen sollten Sie die Azure Cognitive Search-Integration mit Azure Cosmos DB verwenden.

Platzhalterindizes

Sie können Platzhalterindizes verwenden, um Abfragen für unbekannte Felder zu unterstützen. Angenommen, Sie verfügen über eine Sammlung mit Daten über Familien.

Hier sehen Sie einen Auszug eines Beispieldokuments in dieser Sammlung:

"children": [
   {
     "firstName": "Henriette Thaulow",
     "grade": "5"
   }
]

Hier sehen Sie ein weiteres Beispiel, diesmal mit etwas anderen Eigenschaften in children:

"children": [
    {
     "familyName": "Merriam",
     "givenName": "Jesse",
     "pets": [
         { "givenName": "Goofy" },
         { "givenName": "Shadow" }
         ]
   },
   {
     "familyName": "Merriam",
     "givenName": "John",
   }
]

In dieser Sammlung können Dokumente viele verschiedene Eigenschaften haben. Wenn Sie alle Daten im Array children indizieren möchten, haben Sie zwei Möglichkeiten: Sie können separate Indizes für jede einzelne Eigenschaft erstellen oder einen einzelnen Platzhalterindex für das gesamte Array children.

Erstellen eines Platzhalterindex

Mit dem folgenden Befehl wird ein Platzhalterindex für alle Eigenschaften in childrenerstellt:

db.coll.createIndex({"children.$**" : 1})

Anders als in MongoDB können von Platzhalterindizes mehrere Felder in Abfrageprädikaten unterstützt werden. Für die Abfrageleistung ist es unerheblich, ob Sie einen einzelnen Platzhalterindex verwenden oder einen separaten Index für jede Eigenschaft erstellen.

Folgende Indextypen lassen sich mit Platzhaltersyntax erstellen:

  • Einzelfeld
  • Geodaten

Indizieren aller Eigenschaften

So erstellen Sie einen Platzhalterindex für alle Felder:

db.coll.createIndex( { "$**" : 1 } )

Mit dem Daten-Explorer im Azure-Portal können Sie auch Indizes mit Platzhalterzeichen erstellen:

Hinzufügen eines Index mit Platzhalterzeichen im Editor für Indizierungsrichtlinien

Hinweis

Wenn Sie gerade mit der Entwicklung beginnen, wird dringend empfohlen, mit einem Platzhalterindex für alle Felder zu beginnen. Dies kann sowohl die Entwicklung als auch die Optimierung von Abfragen vereinfachen.

Dokumente mit vielen Feldern können eine hohe Gebühr für Anforderungseinheiten (Request Unit, RU) für Schreibvorgänge und Updates aufweisen. Bei schreibintensiven Workloads empfiehlt es sich daher, Pfade einzeln zu indizieren, anstatt Platzhalterindizes zu verwenden.

Einschränkungen

Folgende Indextypen oder Eigenschaften werden von Platzhalterindizes nicht unterstützt:

  • Verbund
  • TTL
  • Eindeutig

Anders als in MongoDB können Platzhalterindizes in der Azure Cosmos DB-API für MongoDB nicht für Folgendes verwendet werden:

  • Erstellen eines Platzhalterindex, der mehrere spezifische Felder einschließt

    db.coll.createIndex(
        { "$**" : 1 },
        { "wildcardProjection " :
            {
               "children.givenName" : 1,
               "children.grade" : 1
            }
        }
    )
    
  • Erstellen eines Platzhalterindex, der mehrere spezifische Felder ausschließt

    db.coll.createIndex(
        { "$**" : 1 },
        { "wildcardProjection" :
            {
               "children.givenName" : 0,
               "children.grade" : 0
            }
        }
    )
    

Alternativ können Sie mehrere Platzhalterindizes erstellen.

Indexeigenschaften

Die folgenden Vorgänge können für Konten mit der Wire-Protokollversion 4.0 und Konten mit früheren Versionen verwendet werden. Sie können noch mehr über unterstützte Indizes und indizierte Eigenschaften erfahren.

Eindeutige Indizes

Eindeutige Indizes sind nützlich, um zu erzwingen, dass zwei oder mehr Dokumente nicht denselben Wert für indizierte Felder enthalten dürfen.

Mit dem folgenden Befehl wird ein eindeutiger Index mit dem Feld student_id erstellt:

globaldb:PRIMARY> db.coll.createIndex( { "student_id" : 1 }, {unique:true} )
{
    "_t" : "CreateIndexesResponse",
    "ok" : 1,
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 4
}

Bei partitionierten Sammlungen muss für die Erstellung eines eindeutigen Indexes der Shardschlüssel (Partitionsschlüssel) angegeben werden. Anders ausgedrückt: Alle eindeutigen Indizes einer Sammlung mit Shards sind zusammengesetzte Indizes, bei denen eines der Felder der Partitionsschlüssel ist.

Mit den folgenden Befehlen erstellen Sie die partitionierte Sammlung coll (der Shardschlüssel lautet university) mit einem eindeutigen Index für die Felder student_id und university:

globaldb:PRIMARY> db.runCommand({shardCollection: db.coll._fullName, key: { university: "hashed"}});
{
    "_t" : "ShardCollectionResponse",
    "ok" : 1,
    "collectionsharded" : "test.coll"
}
globaldb:PRIMARY> db.coll.createIndex( { "university" : 1, "student_id" : 1 }, {unique:true});
{
    "_t" : "CreateIndexesResponse",
    "ok" : 1,
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 3,
    "numIndexesAfter" : 4
}

Im vorherigen Beispiel wird beim Weglassen der "university":1-Klausel folgende Fehlermeldung zurückgegeben:

cannot create unique index over {student_id : 1.0} with shard key pattern { university : 1.0 }

Einschränkungen

Eindeutige Indizes müssen erstellt werden, während die Sammlung leer ist.

TTL-Indizes

Um den Dokumentablauf in einer bestimmten Sammlung zu aktivieren, müssen Sie einen TTL-Index (Time To Live, Gültigkeitsdauer) erstellen. Ein TTL-Index ist ein Index für das Feld _ts mit einem Wert für expireAfterSeconds.

Beispiel:

globaldb:PRIMARY> db.coll.createIndex({"_ts":1}, {expireAfterSeconds: 10})

Der obige Befehl löscht alle Dokumente in der Sammlung db.coll, die nicht innerhalb der letzten zehn Sekunden geändert wurden.

Hinweis

_ts ist ein Azure Cosmos DB-spezifisches Feld, auf das nicht über MongoDB-Clients zugegriffen werden kann. Dies ist eine reservierte Eigenschaft (Systemeigenschaft), die den Zeitstempel der letzten Änderung eines Dokuments enthält.

Nachverfolgen des Indizierungsfortschritts

Version 3.6 und höher der Azure Cosmos DB-API für MongoDB unterstützt den Befehl currentOp() zum Nachverfolgen des Indizierungsfortschritts für eine Datenbankinstanz. Dieser Befehl gibt ein Dokument zurück, das Informationen zu den aktuell in Bearbeitung befindlichen Vorgängen in einer Datenbankinstanz enthält. Verwenden Sie den Befehl currentOp, um alle laufenden Vorgänge in der nativen MongoDB-Datenbank zu verfolgen. In der Azure Cosmos DB-API für MongoDB unterstützt dieser Befehl nur die Nachverfolgung des Indizierungsvorgangs.

Im Folgenden werden einige Beispiele zur Verwendung des Befehls currentOp zur Nachverfolgung des Indizierungsfortschritts gezeigt:

  • Abrufen des Indexfortschritts für eine Sammlung:

    db.currentOp({"command.createIndexes": <collectionName>, "command.$db": <databaseName>})
    
  • Abrufen des Indizierungsfortschritts für alle Sammlungen in einer Datenbank:

    db.currentOp({"command.$db": <databaseName>})
    
  • Abrufen des Indizierungsfortschritts für alle Datenbanken und Sammlungen in einem Azure Cosmos-Konto:

    db.currentOp({"command.createIndexes": { $exists : true } })
    

Beispiele für die Ausgabe des Indizierungsfortschritts

Die Details zum Indizierungsfortschritt zeigen den Fortschritt des aktuellen Indizierungsvorgangs in Prozent an. Im folgenden Beispiel wird das Format des ausgegebenen Dokuments für verschiedene Phasen des Indizierungsfortschritts veranschaulicht:

  • Wenn ein Indizierungsvorgang für die Sammlung „foo“ und die Datenbank „bar“ einen Fortschritt von 60 % aufweist, wird das folgende Dokument ausgegeben. Im Feld Inprog[0].progress.total wird 100 als Zielprozentsatz für den Abschluss angezeigt.

    {
          "inprog" : [
          {
                  ………………...
                  "command" : {
                          "createIndexes" : foo
                          "indexes" :[ ],
                          "$db" : bar
                  },
                  "msg" : "Index Build (background) Index Build (background): 60 %",
                  "progress" : {
                          "done" : 60,
                          "total" : 100
                  },
                  …………..…..
          }
          ],
          "ok" : 1
    }
    
  • Bei einem Indizierungsvorgang, der erst für die Sammlung „foo“ und die Datenbank „bar“ gestartet wurde, zeigt das Ausgabedokument einen Fortschritt von 0 % an, bis ein messbarer Wert erreicht wurde.

    {
          "inprog" : [
          {
                  ………………...
                  "command" : {
                          "createIndexes" : foo
                          "indexes" :[ ],
                          "$db" : bar
                  },
                  "msg" : "Index Build (background) Index Build (background): 0 %",
                  "progress" : {
                          "done" : 0,
                          "total" : 100
                  },
                  …………..…..
          }
          ],
         "ok" : 1
    }
    
  • Wenn der aktive Indizierungsvorgang abgeschlossen wird, zeigt das Ausgabedokument leere inprog-Vorgänge an.

    {
        "inprog" : [],
        "ok" : 1
    }
    

Indexaktualisierungen im Hintergrund

Unabhängig von dem für die Hintergrund-Indexeigenschaft angegebenen Wert werden Indexaktualisierungen immer im Hintergrund durchgeführt. Da Indexaktualisierungen Anforderungseinheiten (Request Units, RUs) mit einer niedrigeren Priorität als andere Datenbankvorgänge nutzen, führen Indexänderungen nicht zu Ausfallzeiten bei Schreib-, Update- oder Löschvorgängen.

Das Hinzufügen eines neuen Indexes hat keine Auswirkung auf die Leseverfügbarkeit. Abfragen verwenden neue Indizes erst dann, wenn die Indextransformation abgeschlossen ist. Während der Indextransformation werden von der Abfrage-Engine weiterhin vorhandene Indizes verwendet, sodass Sie während der Indextransformation eine ähnliche Leseleistung beobachten werden wie vor dem Einleiten der Indexänderung. Beim Hinzufügen neuer Indizes besteht auch kein Risiko, unvollständige oder inkonsistente Abfrageergebnisse zu erhalten.

Wenn Indizes entfernt und sofort Abfragen ausgeführt werden, die nach den gelöschten Indizes filtern, können die Ergebnisse inkonsistent und unvollständig sein, solange die Indextransformation nicht abgeschlossen ist. Wenn Sie Indizes entfernen, bietet die Abfrage-Engine keine konsistenten oder vollständigen Ergebnisse, falls Abfragen nach diesen soeben entfernten Indizes filtern. Die meisten Entwickler löschen keine Indizes und versuchen dann sofort, Abfragen dafür auszuführen, sodass diese Situation in der Praxis eher unwahrscheinlich ist.

ReIndex-Befehl

Mit dem reIndex-Befehl werden alle Indizes in einer Sammlung neu erstellt. In einigen seltenen Fällen können Probleme mit der Abfrageleistung oder andere Indexprobleme in Ihrer Sammlung durch Ausführen des Befehls reIndex gelöst werden. Bei Problemen mit der Indizierung wird empfohlen, die Indizes mit dem Befehl reIndex neu zu erstellen.

Verwenden Sie für die Ausführung des reIndex-Befehls die folgende Syntax:

db.runCommand({ reIndex: <collection> })

Mithilfe der folgenden Syntax können Sie überprüfen, ob die Ausführung des Befehls reIndex die Abfrageleistung in Ihrer Sammlung verbessern würde:

db.runCommand({"customAction":"GetCollection",collection:<collection>, showIndexes:true})

Beispielausgabe:

{
        "database" : "myDB",
        "collection" : "myCollection",
        "provisionedThroughput" : 400,
        "indexes" : [
                {
                        "v" : 1,
                        "key" : {
                                "_id" : 1
                        },
                        "name" : "_id_",
                        "ns" : "myDB.myCollection",
                        "requiresReIndex" : true
                },
                {
                        "v" : 1,
                        "key" : {
                                "b.$**" : 1
                        },
                        "name" : "b.$**_1",
                        "ns" : "myDB.myCollection",
                        "requiresReIndex" : true
                }
        ],
        "ok" : 1
}

Wenn reIndex die Abfrageleistung verbessert, ist für requiresReIndex der Wert „true“ angegeben. Wenn reIndex die Abfrageleistung nicht verbessert, wird diese Eigenschaft ausgelassen.

Migrieren von Sammlungen mit Indizes

Derzeit ist die Erstellung von eindeutigen Indizes nur möglich, wenn die Sammlung keine Dokumente enthält. Bei gängigen MongoDB-Migrationstools wird versucht, die eindeutigen Indizes nach dem Importieren der Daten zu erstellen. Um dieses Problem zu umgehen, können Sie die entsprechenden Sammlungen und eindeutigen Indizes manuell erstellen, damit das Migrationstool dies nicht versucht. (Sie können dieses Verhalten für mongorestore erzielen, indem Sie das --noIndexRestore-Flag an der Befehlszeile verwenden.)

Indizierung für MongoDB-Version 3.2

Bei Azure Cosmos-Konten, die mit Version 3.2 des MongoDB-Wire-Protokolls kompatibel sind, weichen die verfügbaren Indizierungsfeatures und Standardwerte ab. Sie können die Version Ihres Kontos überprüfen und eine Upgrade auf Version 3.6 durchführen.

Wenn Sie Version 3.2 verwenden, beachten Sie die in diesem Abschnitt erläuterten wichtigen Unterschiede zu den Versionen 3.6 und höher.

Löschen der Standardindizes (Version 3.2)

Anders als bei den Versionen 3.6 und höher der Azure Cosmos DB-API für MongoDB werden in der Version 3.2 standardmäßig alle Eigenschaften indiziert. Mit dem folgenden Befehl können Sie diese Standardindizes für eine Sammlung (coll) löschen:

> db.coll.dropIndexes()
{ "_t" : "DropIndexesResponse", "ok" : 1, "nIndexesWas" : 3 }

Nachdem Sie die Standardindizes gelöscht haben, können Sie zusätzliche Indizes wie in Version 3.6 und höher hinzufügen.

Zusammengesetzte Indizes (Version 3.2)

Zusammengesetzte Indizes enthalten Verweise auf mehrere Felder eines Dokuments. Wenn Sie einen zusammengesetzten Index erstellen möchten, führen Sie ein Upgrade auf Version 3.6 oder 4.0 durch.

Platzhalterindizes (Version 3.2)

Wenn Sie einen Platzhalterindex erstellen möchten, führen Sie ein Upgrade auf Version 4.0 oder 3.6 durch.

Nächste Schritte