Azure Cosmos DB für MongoDB-Indizes
Indizes sind Datenstrukturen, mit denen Abfragen schneller auf Ihre Dokumente zugreifen können. Azure Cosmos DB for MongoDB nutzt die wichtigsten Funktionen der Indexverwaltung von Azure Cosmos DB. In dieser Lerneinheit stellen wir Ihnen verschiedene Arten von Indizes vor und zeigen Ihnen, wie Sie diese über den Daten-Explorer im Azure-Portal oder programmgesteuert mithilfe von Sammlungsbefehlen einrichten können. Indizes werden auf der Sammlungsebene eingerichtet.
Standardmäßig indiziert die Azure Cosmos DB für MongoDB automatisch das Feld _id. Eindeutigkeit wird automatisch anhand des Felds _id pro Shardschlüssel erzwungen.
Betrachten wir die verschiedenen Arten von Indizes, die von der Azure Cosmos DB für MongoDB unterstützt werden.
Indextypen
Einzelfeldindizes
Wie der Name bereits vermuten lässt, handelt es sich bei Einzelfeldindizes um Indizes, die für ein einziges Feld erstellt werden. Bei Einzelfeldindizes spielt die Reihenfolge (aufsteigend/absteigend) keine Rolle. Eine Abfrage kann mehrere Einzelfeldindizes verwenden, sofern verfügbar. Pro Sammlung gilt ein Limit von 500 Einzelfeldindizes.
Sehen wir uns einige Methoden für das Erstellen von Einzelfeldindizes an. Angenommen, die Datenbank inventory enthält eine Sammlung namens products, und wir möchten einen Einzelfeldindex für die Spalte name und einen separaten Einzelfeldindex für die Spalte quantity erstellen.
Erstellen Sie von Einzelfeldindizes mithilfe der Registerkarte „Indexrichtlinie“ im Azure-Portal
Wählen Sie im Azure-Portal unter Ihrer Azure Cosmos DB für die MongoDB-Datenbank die Option „Daten-Explorer“ aus.
- Erweitern Sie inventory und dann products, und wählen Sie Einstellungen aus.
- Wählen Sie die Registerkarte Indizierungsrichtlinie aus. Beachten Sie, dass standardmäßig bereits zwei Indizes erstellt worden sein sollten: der bereits erwähnte Einzelfeldindex _id und der
$**-Platzhalterindex, den wir später besprechen werden. Diese Indizes können Sie vorerst ignorieren. - Geben Sie im ersten Textfeld name ein, und wählen Sie im Dropdownmenü die Option Einzelnes Feld aus.
- Geben Sie im nächsten Textfeld quantity ein, und wählen Sie im Dropdownmenü die Option Einzelnes Feld aus.
- Wählen Sie das Symbol „Speichern“ aus.
Erstellen von Einzelfeldindizes mithilfe der MongoDB-Shell
Öffnen Sie die Mongo-Shell, und vergewissern Sie sich, dass mithilfe der Kontoverbindungszeichenfolge auf Ihr Konto für die Azure Cosmos DB für MongoDB verwiesen wird.
Führen Sie die folgenden Befehle aus, um die beiden Indizes hinzuzufügen.
// change to the inventory database
use inventory
// add name, and quantity indexes to the products collection
db.products.createIndex({name:1})
db.products.createIndex({quantity:1})
// look at the list of indexes to see the two new indexes
db.products.getIndexes()
Diese getIndexes-Auflistungsfunktion sollte ein ähnliches Ergebnis liefern wie das folgende:
[
{ v: 1, key: { _id: 1 }, name: '_id_', ns: 'inventory.products' },
{ v: 1, key: { '$**': 1 }, name: '$**_1', ns: 'inventory.products' },
{ v: 1, key: { name: 1 }, name: 'name_1', ns: 'inventory.products' },
{ v: 1, key: { quantity: 1 }, name: 'quantity_1', ns: 'inventory.products' }
]
Programmgesteuertes Erstellen von Einzelfeldindizes
Das folgende Skript erstellt einen Einzelfeldindex.
Node.js
// connect to the database "inventory"
var InventoryDatabase = mongoClient.db("inventory");
// connect to the collection "products"
var productscollection = InventoryDatabase.collection('products');
// add name, and quantity indexes to the products collection
var resultn = await productscollection.createIndex({ name: 1 });
var resultq = await productscollection.createIndex({ quantity: 1 });
Java
// connect to the database "inventory"
MongoDatabase InventoryDatabase = mongo.getDatabase("inventory");
// connect to the collection "products"
MongoCollection productscollection = InventoryDatabase.getCollection("products");
// add name, and quantity indexes to the products collection
productscollection.createIndex(Indexes.ascending("name"));
productscollection.createIndex(Indexes.ascending("quantity"));
Python
# connect to the database "inventory"
InventoryDatabase = client["inventory"]
# connect to the collection "products"
productscollection = InventoryDatabase["products"]
# add name, and quantity indexes to the products collection
productscollection.create_index([ ("name", 1) ])
productscollection.create_index([ ("quantity", 1) ])
C#
// connect to the database "inventory"
var InventoryDatabase = mongoClient.GetDatabase("inventory");
// connect to the collection "products"
var productscollection = InventoryDatabase.GetCollection<Products>("products");
// add name, and quantity indexes to the products collection
productscollection.Indexes.CreateOneAsync(Builders<Products>.IndexKeys.Ascending(_ => _.name));
productscollection.Indexes.CreateOneAsync(Builders<Products>.IndexKeys.Ascending(_ => _.quantity));
Zusammengesetzte Indizes
Zusammengesetzte Indizes werden immer dann benötigt, wenn Ihre Abfragen gleichzeitig nach mehreren Feldern sortieren müssen. Wenn Sie nach mehreren Feldern filtern müssen, erstellen Sie einfach einen Einzelfeldindex für jedes Feld im Filter. Auf diese Weise senken Sie die Indizierungskosten. Abgesehen davon gilt Folgendes: Wenn ein zusammengesetzter Index die Filterfelder einer Abfrage enthält, sind die Filterkosten bei Verwendung des zusammengesetzten Index genauso hoch wie bei Verwendung von Einzelfeldindizes für jedes Feld im Filter.
Zusammengesetzte Indizes können nicht für geschachtelte Eigenschaften oder Arrays erstellt werden.
Im Gegensatz zu Einzelfeldindizes, bei denen die Indexreihenfolge irrelevant ist, muss die Reihenfolge der Felder bei einem zusammengesetzten Index mit der Abfrage übereinstimmen. Angenommen, Sie erstellen den folgenden zusammengesetzten Index, der doctors nach Vorname und dann nach Nachname sortiert.
db.doctors.createIndex({firstName:1,lastName:1})
Nehmen wir weiterhin an, dass Sie alle Ärzte nach Nachname und dann nach Vorname zurückgeben möchten.
db.doctors.find().sort({lastName:1,firstName:1})
Der vorherige zusammengesetzte Index würde nicht funktionieren, Sie benötigen den folgenden Index.
db.doctors.createIndex({lastName:1,firstName:1})
Ein weiterer nützlicher Aspekt von zusammengesetzten Indizes ist, dass sie auch für eine umgekehrte Sortierung genutzt werden können. Der vorherige Index funktioniert also auch, um alle Ärzte absteigend nach dem Nachnamen und dann absteigend nach dem Vornamen zu sortieren (-1 steht für eine absteigende Sortierung).
db.doctors.find().sort({lastName:-1,firstName:-1})
Hinweis
Sie können über das Azure-Portal keinen zusammengesetzten Index erstellen.
Angenommen, wir möchten einen zusammengesetzten Index absteigend nach lastName und absteigend nach firstName für die Sammlung doctors in der Datenbank employees hinzufügen.
Erstellen von zusammengesetzten Indizes mithilfe der MongoDB-Shell
Öffnen Sie die Mongo-Shell, und vergewissern Sie sich, dass mithilfe der Kontoverbindungszeichenfolge auf Ihr Konto für die Azure Cosmos DB für MongoDB verwiesen wird.
Führen Sie die folgenden Befehle aus, um die beiden Indizes hinzuzufügen.
// change to the employees database
use inventory
// add the lastName, firstName compound index to the doctors collection
db.doctors.createIndex({lastName:-1,firstName:-1})
// look at the list of indexes to see the new compound indexes
db.products.getIndexes()
Diese getIndexes-Auflistungsfunktion sollte ein ähnliches Ergebnis liefern wie das folgende:
[
{ v: 1, key: { _id: 1 }, name: '_id_', ns: 'employees.doctors' },
{ v: 1, key: { '$**': 1 }, name: '$**_1', ns: 'employees.doctors' },
{ v: 1, key: { lastName: -1, firstName: -1 }, name: 'lastName_-1_firstName_-1',ns: 'employees.doctors' }
]
Programmgesteuertes Erstellen von zusammengesetzten Indizes
Das folgende Skript erstellt einen Einzelfeldindex.
Node.js
// connect to the database "employees"
var EmployeeDatabase = mongoClient.db("employees");
// connect to the collection "doctors"
var doctorscollection = EmployeeDatabase.collection('doctors');
// add the lastName, firstName compound indexes to the doctors collection
var resultd = await doctorscollection.createIndex({lastName:-1,firstName:-1});
Java
// connect to the database "employees"
MongoDatabase EmployeeDatabase = mongo.getDatabase("employees");
// connect to the collection "doctors"
MongoCollection doctorscollection = EmployeeDatabase.getCollection("doctors");
// add the lastName, firstName compound indexes to the doctors collection
doctorscollection.createIndex(Indexes.descending("lastName","firstName"));
Python
# connect to the database "employees"
EmployeeDatabase = client["employees"]
# connect to the collection "doctors"
doctorscollection = EmployeeDatabase["doctors"]
# add the lastName, firstName compound indexes to the doctors collection
doctorscollection.create_index([ ("lastName",-1), ("firstName",-1) ])
C#
// connect to the database "employees"
var EmployeeDatabase = mongoClient.GetDatabase("employees");
// connect to the collection "doctors"
var doctorscollection = EmployeeDatabase.GetCollection<Employees>("doctors");
// add the lastName, firstName compound indexes to the doctors collection
doctorscollection.Indexes.CreateOneAsync(Builders<Employees>.IndexKeys
.Descending(_ => _.lastName)
.Descending(_ => _.firstName));
Platzhalterindizes
Eine der Eigenschaften von NoSQL ist das Fehlen eines Schemas. Das bedeutet, dass Sie möglicherweise nicht immer alle Felder in Ihren Dokumenten im Voraus kennen. Platzhalterindizes ermöglichen es Ihnen, Abfragen mit unbekannten Feldern oder bei Dokumenten die Möglichkeit vieler verschiedener Eigenschaften zu unterstützen. Sehen wir uns nachfolgend zwei Dokumente in einer Sammlung namens school an.
"Students":
[
{
"StudentName": "John Smith",
"Mayor": "Undefined",
"Classes":
[
{
"ClassName": "History",
"Level":100,
"Teacher": "Mike Michael"
},
{
"ClassName": "Chemistry",
"Level": 101,
"Teacher": "Yi Yan",
"Lab": "Chem Lab 101"
}
]
}
]
"Students":
[
{
"FirstName": "John",
"LastName": "Smith",
"GPA": 3.85,
"FavoriteClasses":
[
{
"ClassName": "Music"
},
{
"ClassName": "Math",
"Level": 101
}
]
}
]
Beide Dokumente enthalten die Eigenschaft Students, aber die untergeordneten Eigenschaften sind alle unterschiedlich. In diesem Fall können wir also alle untergeordneten Eigenschaften von Students indizieren. Dazu führen Sie in der Mongo-Shell den folgenden Befehl aus.
db.school.createIndex({"Students.$**" : 1})
Wir haben vorhin bereits einen Platzhalterindex kennengelernt, den Index $** im Screenshot zu Beginn dieser Lerneinheit. Mit dem Platzhalterindex $** werden alle Felder in der Sammlung indiziert. Wir empfehlen, diesen Index bereits zu Beginn der Entwicklung Ihrer Datenbank-App zu verwenden bzw. spätestens dann, wenn Sie wissen, wie Ihre Sammlung abgefragt werden soll. Wenn Ihre Dokumente allerdings viele Felder enthalten, kann die Beibehaltung dieses Platzhalterindexes zu hohen RU-Gebühren (Request Units, Anforderungseinheiten) für Schreibvorgänge und Aktualisierungen führen. Erwägen Sie die in Umgebungen mit hoher Schreiblast die Verwendung einzelner Indizes anstelle eines zusammengesetzten Indexes.
Indexeigenschaften
Die Azure Cosmos DB für MongoDB unterstützt je nach Version verschiedene Indexeigenschaften. Wir werden uns hier einige davon ansehen. Weitere Informationen finden Sie im Artikel Unterstützte Indizes und indizierte Eigenschaften.
Eindeutige Indizes
Um Eindeutigkeit in Ihren Dokumenten zu erzwingen, müssen Sie bei der Indexdefinition die Eigenschaft unique auf true festlegen. Angenommen, wir möchten sicherstellen, dass die deviceId in unserer IOT-Sammlung eindeutig ist. Zur Gewährleistung der Eindeutigkeit würden wir mithilfe der Mongo-Shell den folgenden Befehl ausführen.
db.IOT.createIndex( { "deviceId" : 1 }, {unique:true} )
Wenn unsere Sammlung in Shards aufgeteilt ist, müssen wir außerdem den Partitionsschlüssel angeben, um einen eindeutigen Index zu erstellen. Das bedeutet, dass unser eindeutiger Index letztendlich ein zusammengesetzter Index sein wird. Nehmen wir an, dass der Shardschlüssel in unserem vorherigen Beispiel locationId lautet. Um den eindeutigen Index zu erstellen, würden wir den folgenden Befehl ausführen.
db.IOT.createIndex( {"locationId": 1, "deviceId" : 1 }, {unique:true} )
Hinweis
Sie können einen eindeutigen Index nur für eine leere Sammlung erstellen.
Eindeutige Teilindizes
Die Azure Cosmos DB für MongoDB gibt uns die Möglichkeit, eindeutige Indizes für eine Teilmenge der Dokumente in unserer Sammlung zu erstellen, die ein durch die Eigenschaft partialFilterExpression definiertes Kriterium erfüllen. Dies erzwingt die Eindeutigkeit aller Dokumente, die die Filterkriterien erfüllen, indem das Einfügen von Duplikaten verhindert wird. Dieser Filter verhindert jedoch nicht die Einfügung eines Dokuments, das die Kriterien nicht erfüllt.
Verwenden Sie zum Erstellen eines Teilindexes die Methode db.collection.createIndex() mit der Option partialFilterExpression und der Einschränkung unique. Die Option partialFilterExpression akzeptiert ein Dokument, das die Filterbedingung anhand eines der folgenden Elemente angibt:
- Gleichheitsausdrücke (z. B. „Feld: Wert“ oder Verwendung des $eq-Operators)
- Ausdruck „$exists: true“
- $gt-, $gte-, $lt-, $lte-Ausdrücke
- $type-Ausdrücke
- $and-Operator nur auf oberster Ebene
Betrachten wir noch einmal unser obiges IOT-Beispiel. Angenommen, die Sammlung enthält IOT-Protokolldaten für mehrere Jahre. Da IOT-Geräte keine Daten zu einem bereits vergangenen Zeitpunkt eingeben, können wir uns darauf beschränken, die Eindeutigkeit für das aktuelle Jahr zu überprüfen. In der Mongo-Shell würden wir den folgenden Befehl ausführen, um diesen eindeutigen Index zu erstellen.
db.IOT.createIndex( { "deviceId" : 1 }, {unique:true, partialFilterExpression:{logYear:{$gte:2022}}} )
Indexaktualisierungen im Hintergrund
Sämtliche Indexaktualisierungen werden stets im Hintergrund durchgeführt. Indexaktualisierungen verbrauchen Anforderungseinheiten (RUs) mit einer niedrigeren Priorität als andere Datenbankvorgänge, sodass sie keine Ausfallzeiten bei Ihren Schreibvorgängen, Aktualisierungen oder Löschvorgängen verursachen.
Das Hinzufügen eines neuen Indexes hat keinen Einfluss auf die Leseverfügbarkeit. Während der Indexerstellung verwendet Azure Cosmos DB die vorhandenen Indizes zur Unterstützung von Abfragen. Das Hinzufügen oder Erstellen von Indizes verursacht keine Inkonsistenzen bei den Abfrageergebnissen.
Weitere Informationen zu MongoDB-Indizes finden Sie im Dokument Verwalten der Indizierung in der Azure Cosmos DB für MongoDB.