Übung: Indizes und Aggregationspipelines
Wir werden das Azure-Portal nutzen, um einen genaueren Blick auf Indizes und Aggregationspipelines zu werfen.
Sie können diese Übung mithilfe einer Sandbox von Microsoft Learn durchführen, die ein temporäres Azure-Abonnement bereitstellt. Zur Aktivierung des Sandbox-Abonnements müssen Sie sich mit einem Microsoft-Konto anmelden. Nach Abschluss dieses Moduls wird das Sandbox-Abonnement automatisch gelöscht. Melden Sie sich nach Aktivierung der Sandbox mit den Anmeldeinformationen für Ihr Sandbox-Abonnement im Azure-Portal an. Stellen Sie sicher, dass Sie sich im Verzeichnis Microsoft Learn Sandbox befinden. Dies wird oben rechts im Portal unter Ihrer Benutzer-ID angezeigt. Falls nicht, klicken Sie auf das Benutzersymbol, und wechseln Sie das Verzeichnis.
Tipp
Wenn Sie möchten, können Sie auch ein eigenes Azure-Abonnement verwenden. Melden Sie sich hierfür mit den Anmeldeinformationen für Ihr Abonnement im Azure-Portal an. Stellen Sie sicher, dass Sie sich im Verzeichnis mit Ihrem Abonnement befinden. Dies wird oben rechts unter Ihrer Benutzer-ID angegeben. Falls nicht, klicken Sie auf das Benutzersymbol, und wechseln Sie das Verzeichnis.
Indizes und Pipelineaggregationen
In dieser Übung werden wir das Azure-Portal nutzen, um anhand einiger Beispiele zu veranschaulichen, wie Indizes die Kosten für unsere Abfragen beeinflussen. Wir verwenden hierbei die Funktionen db.collection.find und db.collection.aggregation. Zunächst erstellen wir über das Azure-Portal unser Azure Cosmos DB für MongoDB-Konto, falls es noch nicht vorhanden ist.
Vorbereiten Ihrer Entwicklungsumgebung
Wenn Sie das Azure Cosmos DB-Konto und die Umgebung noch nicht vorbereitet haben, mit denen Sie in diesem Lab arbeiten, führen Sie die folgenden Schritte aus. Andernfalls wechseln Sie zum Abschnitt Indizes und ihre Auswirkungen.
Kopieren Sie in Azure Cloud Shell die folgenden Befehle, und fügen Sie sie ein.
Wenn Sie die Sandbox verwenden, wurde bereits eine Ressourcengruppe für Sie erstellt. In diesem Fall führen Sie das folgende Skript aus.
# Create an Azure Cosmos DB for MongoDB account and add the customer collection git clone https://github.com/MicrosoftLearning/mslearn-cosmosdb.git GitRepositoryRoot=$(pwd) bash "$GitRepositoryRoot/mslearn-cosmosdb/api-for-mongodb/02-indexes-and-aggregation-pipelines/init.sh"Wenn Sie bereits über eine Ressourcengruppe verfügen, die Sie in Ihrer Umgebung verwenden möchten, ersetzen Sie die Zeichenfolge YOURRESOURCEGROUPNAMEHERE unten durch den Namen Ihrer Ressourcengruppe. Wenn Sie die Sandbox nicht verwenden, müssen Sie den Befehl az login ausführen, bevor Sie das nachstehende Bash-Skript init ausführen.
# Create an Azure Cosmos DB for MongoDB account and add the customer collection git clone https://github.com/MicrosoftLearning/mslearn-cosmosdb.git GitRepositoryRoot=$(pwd) # Replace YOURRESOURCEGROUPNAMEHERE for the name of your Resource Group bash "$GitRepositoryRoot/mslearn-cosmosdb/api-for-mongodb/02-indexes-and-aggregation-pipelines/init.sh" -r YOURRESOURCEGROUPNAMEHERE
Tipp
Wenn Sie den Speicherort angeben möchten, an dem Sie Ihre Datenbank- und Speicherobjekte erstellen möchten, fügen Sie einen -l LOCATIONNAME-Parameter zum init.sh-Aufruf hinzu.
Hinweis
Dieses Bash-Skript erstellt die Azure Cosmos DB für das MongoDB-Konto und kopiert die Kundensammlung in dieses Konto. Die Erstellung des Kontos dauert fünf bis zehn Minuten. Sie haben also genügend Zeit, sich eine Tasse Kaffee oder Tee zu holen.
Da Sie das Azure-Portal mit der Sandbox verwenden, vergessen Sie nicht, das Verzeichnis im Azure-Portal zu wechseln, um die von der Sandbox erstellte Ressourcengruppe zu verwenden.
Schließen Sie die Sandbox nicht. Melden Sie sich in einem anderen Browserfenster oder auf einer anderen Registerkarte mit demselben Konto beim Azure-Portal an, mit dem Sie die Sandbox verknüpft haben.
Überprüfen Sie in der oberen rechten Ecke des Azure-Portals das Verzeichnis, bei dem Sie angemeldet sind. Wenn es auf das Standardverzeichnis oder etwas anderes als das Verzeichnis Microsoft Learn-Sandbox verweist, fahren Sie mit dem nächsten Schritt fort. Führen Sie andernfalls die Schritte im nächsten Abschnitt aus.
Klicken Sie auf das Benutzersymbol in der oberen rechten Ecke neben Ihrem Anmeldenamen. Wählen Sie dann Verzeichnis wechseln aus.
Klicken Sie auf die Schaltfläche Wechseln. Anhand der oberen rechten Ecke werden Sie feststellen, dass Sie sich jetzt im Microsoft Learn-Sandboxverzeichnis befinden.
Fahren Sie mit dem Lab fort.
Indizes und ihre Auswirkungen
Wir verwenden das Azure-Portal, um einige Abfragen durchzuführen und deren Auswirkungen zu überprüfen.
Navigieren Sie im Azure-Portal zu Ihrem Azure Cosmos DB API für Mongo DB-Konto.
Wählen Sie unter „Daten-Explorer“ die Datenbank database-v1 und die Sammlung customer aus.
Wählen Sie auf der rechten Seite des Sammlungsmenüs die Optionen >_ Neue Shell aus.
Führen Sie eine einfache Abfrage aus, um alle Dokumente für Kunden mit dem Nachnamen Benson zurückzugeben. Führen Sie dazu an der Shell-Eingabeaufforderung die folgende Abfrage aus.
db.customer.find({lastName: "Benson"})Diese Abfrage meldet zunächst einen Verbrauch von 337,38 RUs für den Vorgang, der Ihnen angezeigte Kostenwert kann jedoch leicht abweichen. Anschließend sollten die folgenden Dokumente zurückgegeben werden.
[ { _id: ObjectId("62b9125f0a967b00dc936a3f"), id: '277EB18F-2886-4E2A-BF92-C3A8A87F27FC', title: 'Ms.', firstName: 'Edna', lastName: 'Benson', emailAddress: 'edna0@adventure-works.com', phoneNumber: '789-555-0189', creationDate: '2013-07-31T00:00:00' }, { _id: ObjectId("62b9125f0a967b00dc9391ae"), id: '45758735-8AB4-4B4E-B161-26F073FB2CA4', title: 'Mr.', firstName: 'Max', lastName: 'Benson', emailAddress: 'max0@adventure-works.com', phoneNumber: '599-555-0160', creationDate: '2011-10-01T00:00:00' }, { _id: ObjectId("62b9125f0a967b00dc939852"), id: 'A1AC6260-F902-472D-8CB3-C9955635DABF', title: 'Mr.', firstName: 'Payton', lastName: 'Benson', emailAddress: 'payton0@adventure-works.com', phoneNumber: '528-555-0183', creationDate: '2011-10-01T00:00:00' } ]Diese Kosten scheinen nicht richtig zu sein. Derzeit befinden sich 19.119 Dokumente in dieser Sammlung, aber die RU-Kosten für diese Abfrage sollten dennoch im einstelligen Bereich liegen.
Überprüfen wir, ob ein Index für das Feld lastName vorhanden ist. Erweitern Sie in der Datenbankstruktur die Datenbank database-v1 und die Sammlung customer, und wählen Sie Einstellungen aus.
Wählen Sie die Registerkarte Indizierungsrichtlinie aus.
Beachten Sie, dass nur ein Index für das Feld _id vorhanden ist, der für jede Sammlung in einer Azure Cosmos DB für MongoDB-Sammlung erstellt wird. Darüber hinaus gibt es keine weiteren Indizes. Das Fehlen von Indizes erklärt unser Problem. Da für die Spalte lastName kein Index vorhanden ist, müssen sämtliche Daten durchsucht werden, um die drei Dokumente zu finden, die unseren Kriterien entsprechen. Fügen wir den benötigten Index jetzt hinzu.
Hierzu platzieren Sie den Spaltennamen lastName unter der Spalte Definition und wählen im Pulldownmenü Typ die Option Einzelnes Feld aus. Wählen Sie anschließend unter dem Menü Speichern aus, um den Index zu erstellen. Sie können auch mehrere Einzelfeldindizes gleichzeitig erstellen.
Hinweis
Sobald Sie Speichern ausgewählt haben, können Sie auf der Registerkarte „Indizierungsrichtlinie“ nach oben scrollen, um den Fortschritt der Indexerstellung anzuzeigen. Es sollte 5–20 Sekunden dauern, um diesen Index zu erstellen. Beachten Sie, dass dieser Vorgang bei sehr großen Indizes mehrere Minuten bis hin zu Stunden dauern kann.
Kehren wir zur Shell zurück. Wenn die Verbindung durch einen Timeout unterbrochen wurde, öffnen Sie einfach eine neue Shell.
Führen Sie die Abfrage erneut aus, um alle Kunden mit dem Nachnamen Benson zurückzugeben.
db.customer.find({lastName: "Benson"})Jetzt sollte ein erheblicher Unterschied bei den Kosten zu sehen sein. Die Abfrage hat die drei erwarteten Dokumente zurückgegeben, und es sollte ein Verbrauch von 4,98 RUs gemeldet werden (möglicherweise erhalten Sie einen leicht anderen Kostenwert).
Versuchen wir noch etwas. Suchen wir nach allen Kunden, die nach 2011 erstellt wurden. Wir wissen bereits im Vorfeld, dass die Leistung sehr schlecht sein wird.
db.customer.find({creationDate: {$gte : "2012-01-01T00:00:00Z"}})Und wie erwartet liegen die Kosten mit 524,73 RUs sehr hoch.
Erstellen wir jetzt den Index für das Feld creationDate mit dem Typ Einzelnes Feld. Nach der Indexerstellung führen wir die Abfrage noch einmal aus.
Die RU-Kosten liegen immer noch im dreistelligen Bereich, d. h. die Abfrage ist weiterhin sehr kostenintensiv. Finden wir heraus, woran das liegt.
Aggregierte Pipelines
Wie viele Dokumente wurden von der vorherigen Abfrage zurückgegeben? Zur Beantwortung dieser Frage benötigen wir eine etwas komplexere Abfrage. Verwenden wir eine Aggregationspipeline, um die Anzahl zu bestimmen. Zuerst müssen wir einen Abgleich mit der Bedingung unserer Aggregation durchführen, anschließend müssen wir zählen, wie viele Dokumente zurückgegeben werden.
Die folgende Aggregation sollte uns das gewünschte Ergebnis liefern. Unsere Vergleichsbedingung ist mit der Bedingung unserer letzten Abfrage identisch. Anschließend führen wir eine Gruppierung nach dem Schlüssel _id durch, da es sich um eine eindeutige Spalte handelt, die uns die Anzahl der eindeutigen Dokumente liefert. In der Gruppenpipeline ermitteln wir die Summe der Dokumente, die dem Filter entsprechen. Abschließend projizieren wir nur das Feld CountNumberOfDocuments und unterdrücken die Spalte _id, die für unsere gewünschten Ergebnisse nicht relevant ist.
db.customer.aggregate( [ { $match: {creationDate: {$gte : "2012-01-01T00:00:00Z"}} }, { $group: { _id: "$_id_" , CountNumberOfDocuments: {$sum:1} } }, { $project: { _id:0 , CountNumberOfDocuments: 1 } } ] )Bei dieser Ausführung müssen einige Dinge beachtet werden. Erstens lagen die Kosten sehr hoch, und zweitens war die Leistung unserer Abfrage nicht viel besser, weil fast so viele Dokumente zurückgegeben wurden, wie in der Sammlung vorhanden waren.
Wenn Sie beide Abfragen so ändern, dass nur nach 2014 erstellte Kunden berücksichtigt werden, (z. B. mit „$gte 1/1/2015“), sollten beide Abfragen sehr kostengünstig sein, da nur 10 Dokumente nach diesem Datum erstellt wurden. Lassen Sie uns dies testen.
Führen wir eine letzte Abfrage durch. Bei dieser Abfrage möchten wir alle Dokumente zurückgeben, die den folgenden Kriterien entsprechen: a) Welche der Kundenkonten verfügt über einen internationalen Gebietscode 1 (11)? b) Welche dieser Konten wurden nach 2013 angelegt und tragen einen Titel in ihrem Namen (z. B. „Herr“, „Frau“ usw.)? c) Die Dokumente müssen alle Originalspalten mit Ausnahme der Spalte _id enthalten. d) Die Dokumente müssen außerdem ein Feld enthalten, das angibt, wie viele Tage nach dem 1. Januar 2022 die Kundenkonten angelegt wurden.
Beginnen Sie mit der Erstellung aller notwendigen Indizes für die Felder title, phoneNumber und creationDate. Erstellen Sie jetzt diese Indizes.
Werfen wir einen Blick auf unsere verschiedenen Pipelines und führen sie dann zusammen.
Betrachten wir zunächst unsere Vergleichsfilter. Wir benötigen einen Filter für die Telefonnummer, einen Filter für das Erstellungsdatum und einen Filter für den Titel.
[ { $match: { creationDate: {$gte: "2014-01-01T00:00:00Z"} , $phoneNumber:{$regex: "1 \\(11\\)"} , title: {$ne:""} } } ]Anschließend könnten wir mithilfe der Gruppenpipeline die Anzahl der Tage seit dem 1.1.2022 berechnen, an dem das Konto eröffnet wurde. Da wir aber nicht wirklich nach einer bestimmten Spalte gruppieren und nur den Datumsunterschied für jedes gefundene Konto berechnen möchten, können wir stattdessen die Projektpipeline verwenden.
[ { $project: { title:1 , firstName:1 , lastName:1 , emailAddress:1 , phoneNumber:1 , creationDate:1, "NumberOfDays":{$toInt: {$divide:[{"$subtract":[ {$toDate:"2022-01-01T00:00:00Z"},{$toDate:"$creationDate"}]},1000*60*60*24]}} , _id:0 } } ]Beachten Sie die Division durch 1000x60x60x24, da die Subtraktion der Daten in Millisekunden erfolgt. Beachten Sie auch, dass das Feld _id nicht zurückgegeben wird.
Lassen Sie uns alle Puzzleteile zusammensetzen. Führen Sie den folgenden Befehl aus.
db.customer.aggregate( [ { $match: { creationDate: {$gte: "2014-01-01T00:00:00Z"} , phoneNumber: {$regex: "1 \\(11\\)"} , title: {$ne:""} } }, { $project: { title:1 , firstName:1 , lastName:1 , emailAddress:1 , phoneNumber:1 , creationDate:1, "NumberOfDays":{$toInt: {$divide:[{"$subtract":[ {$toDate:"2022-01-01T00:00:00Z"},{$toDate:"$creationDate"}]},1000*60*60*24]}} , _id:0 } } ] )Damit sollten die folgenden drei Zeilen zurückgegeben werden. Ohne die Erstellung der drei Indizes hätten sich die Kosten auf etwa 460 RUs belaufen, aber mit unseren Indizes liegen die Kosten eher bei 7 RUs.
[ { title: 'Mr.', firstName: 'Jay', lastName: 'Fluegel', emailAddress: 'jay2@adventure-works.com', phoneNumber: '1 (11) 500 555-0119', creationDate: '2014-05-01T00:00:00', NumberOfDays: 2802 }, { title: 'Mrs.', firstName: 'Barbara', lastName: 'Nara', emailAddress: 'barbara45@adventure-works.com', phoneNumber: '1 (11) 500 555-0144', creationDate: '2014-01-08T00:00:00', NumberOfDays: 2915 }, { title: 'Sra.', firstName: 'Pilar', lastName: 'Ackerman', emailAddress: 'pilar1@adventure-works.com', phoneNumber: '1 (11) 500 555-0132', creationDate: '2015-04-15T16:33:33', NumberOfDays: 2452 } ]
Wie bei den meisten Datenbanksystemen sorgt die richtige Indizierung für eine optimierte Abfrageausführung und reduziert die Kosten erheblich. Außerdem konnten wir dank der eingeführten Aggregationspipelines problemlos komplexe Abfragen erstellen. Diese Pipelines können zwar hohe Ausführungskosten verursachen, aber mit der richtigen Indizierungsstruktur können Sie auch die Kosten für die Aggregationspipeline drastisch senken.