Abrufen von SQL-Abfrageausführungsmetriken und Analysieren der Abfrageleistung mit dem .NET SDK
GILT FÜR: NoSQL
In diesem Artikel wird erläutert, wie Sie mithilfe der über das .NET SDK abgerufenen Metrik ServerSideCumulativeMetricsein Profil für die SQL-Abfrageleistung in Azure Cosmos DB erstellen. ServerSideCumulativeMetrics
ist ein stark typisiertes Objekt mit Informationen zur Back-End-Abfrageausführung. Es enthält kumulative Metriken, die für alle physischen Partitionen für die Anforderung aggregiert werden, eine Liste der Metriken für jede physische Partition und die Gesamtkosten der Anforderung. Diese Metriken werden im Artikel Optimieren der Abfrageleistung ausführlicher dokumentiert.
Abrufen von Abfragemetriken
Abfragemetriken sind ab Version 3.36.0 als stark typisiertes Objekt im .NET SDK verfügbar. Vor dieser Version oder bei Verwendung einer anderen SDK-Sprache können Sie Abfragemetriken abrufen, indem Sie Diagnostics
analysieren. Das folgende Codebeispiel zeigt, wie Sie ServerSideCumulativeMetrics
aus Diagnostics
in FeedResponse abrufen:
CosmosClient client = new CosmosClient(myCosmosEndpoint, myCosmosKey);
Container container = client.GetDatabase(myDatabaseName).GetContainer(myContainerName);
QueryDefinition query = new QueryDefinition("SELECT TOP 5 * FROM c");
FeedIterator<MyClass> feedIterator = container.GetItemQueryIterator<MyClass>(query);
while (feedIterator.HasMoreResults)
{
// Execute one continuation of the query
FeedResponse<MyClass> feedResponse = await feedIterator.ReadNextAsync();
// Retrieve the ServerSideCumulativeMetrics object from the FeedResponse
ServerSideCumulativeMetrics metrics = feedResponse.Diagnostics.GetQueryMetrics();
}
Sie können Abfragemetriken aus dem FeedResponse
-Element einer LINQ-Abfrage auch mithilfe der ToFeedIterator()
-Methode abrufen:
FeedIterator<MyClass> feedIterator = container.GetItemLinqQueryable<MyClass>()
.Take(5)
.ToFeedIterator();
while (feedIterator.HasMoreResults)
{
FeedResponse<MyClass> feedResponse = await feedIterator.ReadNextAsync();
ServerSideCumulativeMetrics metrics = feedResponse.Diagnostics.GetQueryMetrics();
}
Kumulative Metriken
ServerSideCumulativeMetrics
enthält eine CumulativeMetrics
-Eigenschaft, die die Abfragemetriken darstellt, die für alle Partitionen für den einzelnen Roundtrip aggregiert wurden.
// Retrieve the ServerSideCumulativeMetrics object from the FeedResponse
ServerSideCumulativeMetrics metrics = feedResponse.Diagnostics.GetQueryMetrics();
// CumulativeMetrics is the metrics for this continuation aggregated over all partitions
ServerSideMetrics cumulativeMetrics = metrics.CumulativeMetrics;
Sie können diese Metriken auch für alle Roundtrips für die Abfrage aggregieren. Im Folgenden sehen Sie ein Beispiel für das Aggregieren der Abfrageausführungszeit für alle Roundtrips für eine bestimmte Abfrage mithilfe von LINQ:
QueryDefinition query = new QueryDefinition("SELECT TOP 5 * FROM c");
FeedIterator<MyClass> feedIterator = container.GetItemQueryIterator<MyClass>(query);
List<ServerSideCumulativeMetrics> metrics = new List<ServerSideCumulativeMetrics>();
TimeSpan cumulativeTime;
while (feedIterator.HasMoreResults)
{
// Execute one continuation of the query
FeedResponse<MyClass> feedResponse = await feedIterator.ReadNextAsync();
// Store the ServerSideCumulativeMetrics object to aggregate values after all round trips
metrics.Add(feedResponse.Diagnostics.GetQueryMetrics());
}
// Aggregate values across trips for metrics of interest
TimeSpan totalTripsExecutionTime = metrics.Aggregate(TimeSpan.Zero, (currentSum, next) => currentSum + next.CumulativeMetrics.TotalTime);
DoSomeLogging(totalTripsExecutionTime);
Partitionierte Metriken
ServerSideCumulativeMetrics
enthält eine PartitionedMetrics
-Eigenschaft, die eine Liste der Metriken pro Partition für den Roundtrip ist. Wenn mehrere physische Partitionen in einem einzelnen Roundtrip erreicht werden, werden Metriken für jede dieser Partitionen in der Liste angezeigt. Partitionierte Metriken werden als ServerSidePartitionedMetrics mit einem eindeutigen Bezeichner für jede physische Partition und Anforderungskosten für diese Partition dargestellt.
// Retrieve the ServerSideCumulativeMetrics object from the FeedResponse
ServerSideCumulativeMetrics metrics = feedResponse.Diagnostics.GetQueryMetrics();
// PartitionedMetrics is a list of per-partition metrics for this continuation
List<ServerSidePartitionedMetrics> partitionedMetrics = metrics.PartitionedMetrics;
Durch das Akkumulieren für alle Roundtrips können Sie mithilfe der Metriken pro Partition feststellen, ob eine bestimmte Partition im Vergleich zu anderen Leistungsprobleme verursacht. Im Folgenden sehen Sie ein Beispiel für das Gruppieren von Partitionsmetriken für jeden Roundtrip mithilfe von LINQ:
QueryDefinition query = new QueryDefinition("SELECT TOP 5 * FROM c");
FeedIterator<MyClass> feedIterator = container.GetItemQueryIterator<MyClass>(query);
List<ServerSideCumulativeMetrics> metrics = new List<ServerSideCumulativeMetrics>();
while (feedIterator.HasMoreResults)
{
// Execute one continuation of the query
FeedResponse<MyClass> feedResponse = await feedIterator.ReadNextAsync();
// Store the ServerSideCumulativeMetrics object to aggregate values after all round trips
metrics.Add(feedResponse.Diagnostics.GetQueryMetrics());
}
// Group metrics by partition key range id
var groupedPartitionMetrics = metrics.SelectMany(m => m.PartitionedMetrics).GroupBy(p => p.PartitionKeyRangeId);
foreach(var partitionGroup in groupedPartitionMetrics)
{
foreach(var tripMetrics in partitionGroup)
{
DoSomethingWithMetrics();
}
}
Abrufen der Anforderungsgebühren für Abfragen
Sie können die von jeder Abfrage verbrauchten Anforderungseinheiten erfassen, um ressourcenintensive Abfragen oder Abfragen zu untersuchen, die einen hohen Durchsatz nutzen. Sie können die Gesamtkosten der Anforderung mithilfe der TotalRequestCharge
-Eigenschaft in ServerSideCumulativeMetrics
erhalten, oder Sie können die Anforderungsgebühr von jeder Partition anhand der Eigenschaft RequestCharge
für jede zurückgegebene ServerSidePartitionedMetrics
anzeigen.
Die Gesamtkosten der Anforderung sind auch mit der RequestCharge
-Eigenschaft in FeedResponse
verfügbar. Weitere Informationen zum Abrufen der Anforderungsgebühr mithilfe des Azure-Portals und verschiedener SDKs finden Sie im Artikel Ermitteln der Gebühr für eine Anforderungseinheit.
QueryDefinition query = new QueryDefinition("SELECT TOP 5 * FROM c");
FeedIterator<MyClass> feedIterator = container.GetItemQueryIterator<MyClass>(query);
while (feedIterator.HasMoreResults)
{
// Execute one continuation of the query
FeedResponse<MyClass> feedResponse = await feedIterator.ReadNextAsync();
double requestCharge = feedResponse.RequestCharge;
// Log the RequestCharge how ever you want.
DoSomeLogging(requestCharge);
}
Abrufen der Abfrageausführungsdauer
Sie können die Abfrageausführungszeit für jeden Roundtrip aus den Abfragemetriken abrufen. Beim Betrachten der Anforderungslatenz ist es wichtig, die Abfrageausführungszeit von anderen Latenzquellen zu unterscheiden, z. B. Netzwerkübertragungszeit. Das folgende Beispiel zeigt, wie Sie die kumulative Abfrageausführungszeit für jeden Roundtrip abrufen:
QueryDefinition query = new QueryDefinition("SELECT TOP 5 * FROM c");
FeedIterator<MyClass> feedIterator = container.GetItemQueryIterator<MyClass>(query);
TimeSpan cumulativeTime;
while (feedIterator.HasMoreResults)
{
// Execute one continuation of the query
FeedResponse<MyClass> feedResponse = await feedIterator.ReadNextAsync();
ServerSideCumulativeMetrics metrics = response.Diagnostics.GetQueryMetrics();
cumulativeTime = metrics.CumulativeMetrics.TotalTime;
}
// Log the elapsed time
DoSomeLogging(cumulativeTime);
Abrufen der Indexauslastung
Die Indexauslastung kann Sie beim Debuggen langsamer Abfragen unterstützen. Bei Abfragen, die das Indexergebnis nicht verwenden können, wird eine vollständige Überprüfung aller Dokumente in einem Container ausgeführt, bevor das Resultset zurückgegeben wird.
Hier ein Beispiel einer Überprüfungsabfrage:
SELECT VALUE c.description
FROM c
WHERE UPPER(c.description) = "BABYFOOD, DESSERT, FRUIT DESSERT, WITHOUT ASCORBIC ACID, JUNIOR"
Der Filter dieser Abfrage verwendet die Systemfunktion UPPER, die nicht über den Index verarbeitet wird. Die Ausführung dieser Abfrage für eine große Sammlung ergab die folgenden Abfragemetriken für die erste Fortsetzung:
QueryMetrics
Retrieved Document Count : 60,951
Retrieved Document Size : 399,998,938 bytes
Output Document Count : 7
Output Document Size : 510 bytes
Index Utilization : 0.00 %
Total Query Execution Time : 4,500.34 milliseconds
Query Preparation Time : 0.2 milliseconds
Index Lookup Time : 0.01 milliseconds
Document Load Time : 4,177.66 milliseconds
Runtime Execution Time : 407.9 milliseconds
Document Write Time : 0.01 milliseconds
Beachten Sie die folgenden Werte der Ausgabe der Abfragemetriken:
Retrieved Document Count : 60,951
Retrieved Document Size : 399,998,938 bytes
Diese Abfrage hat 60.951 Dokumente geladen, die insgesamt 399.998.938 Bytes umfassten. Das Laden so vieler Bytes führt zu hohen Kosten oder Gebühren für Anforderungseinheiten. Außerdem nimmt die Ausführung der Abfrage viel Zeit in Anspruch, was anhand der Eigenschaft für die insgesamt benötigte Zeit („Total Query Execution Time“) deutlich wird:
Total Query Execution Time : 4,500.34 milliseconds
Dies bedeutet, dass die Ausführung der Abfrage 4,5 Sekunden dauerte (und das war nur eine Fortsetzung).
Vermeiden Sie die Verwendung von UPPER im Filter, um diese Beispielabfrage zu optimieren. Wenn Dokumente erstellt oder aktualisiert werden, müssen stattdessen die Werte von c.description
in Großbuchstaben eingefügt werden. Die Abfrage sieht dann wie folgt aus:
SELECT VALUE c.description
FROM c
WHERE c.description = "BABYFOOD, DESSERT, FRUIT DESSERT, WITHOUT ASCORBIC ACID, JUNIOR"
Diese Abfrage kann jetzt über den Index verarbeitet werden. Alternativ können Sie berechnete Eigenschaften verwenden, um die Ergebnisse von Systemfunktionen oder komplexen Berechnungen zu indizieren, die andernfalls zu einer vollständigen Überprüfung führen würden.
Weitere Informationen zum Optimieren der Abfrageleistung finden Sie im Artikel Optimieren der Abfrageleistung.