使用 .NET SDK 取得 SQL 查詢執行計量和分析查詢效能
適用於:NoSQL
本文呈現如何使用從 .NET SDK 擷取的 ServerSideCumulativeMetrics 以在 Azure Cosmos DB 上分析 SQL 查詢效能。 ServerSideCumulativeMetrics
是強型別物件,具有後端查詢執行的相關資訊。 它包含累計計量,這些計量會匯總至要求的所有實體分割區、每個實體分割區的計量清單,以及要求費用總計。 微調查詢效能一文詳述這些計量。
取得查詢計量
從 3.36.0 版開始的 .NET SDK 中,查詢計量可作為強型別物件。 在此版本之前,或如果您要使用不同的 SDK 語言,則可以剖析 Diagnostics
以擷取查詢計量。 下列程式碼範例顯示如何從 FeedResponse 中的 Diagnostics
擷取 ServerSideCumulativeMetrics
:
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();
}
您也可以使用 ToFeedIterator()
方法以從 LINQ 查詢的 FeedResponse
取得查詢計量:
FeedIterator<MyClass> feedIterator = container.GetItemLinqQueryable<MyClass>()
.Take(5)
.ToFeedIterator();
while (feedIterator.HasMoreResults)
{
FeedResponse<MyClass> feedResponse = await feedIterator.ReadNextAsync();
ServerSideCumulativeMetrics metrics = feedResponse.Diagnostics.GetQueryMetrics();
}
累計計量
ServerSideCumulativeMetrics
包含 CumulativeMetrics
屬性,而此屬性代表針對單一來回行程的所有分割區所彙總的查詢計量。
// 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;
您也可以跨查詢的所有來回行程來彙總這些計量。 下列範例顯示如何使用 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);
已分割的計量
ServerSideCumulativeMetrics
包含 PartitionedMetrics
屬性,而此屬性是來回行程的每個分割區計量清單。 如果單一來回行程中達到多個實體分割區,則其都會出現在清單中。 數據分割計量會以 ServerSidePartitionedMetrics 表示,每個實體分割區的唯一標識符,以及該分割區的要求費用。
// 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;
針對所有來回行程累計時,每個分割區計量可讓您與其他分割區進行比較,以查看效能問題是否起因於特定分割區。 下列範例顯示如何使用 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();
}
}
取得查詢要求費用
您可以擷取每個查詢所耗用的要求單位,以調查耗費資源的查詢,或耗用高輸送量的查詢。 您可以使用 中的 ServerSideCumulativeMetrics
屬性取得要求費用TotalRequestCharge
總計,也可以使用每個傳回的屬性查看每個ServerSidePartitionedMetrics
分割RequestCharge
區的要求費用。
您也可以使用 中的FeedResponse
屬性來取得RequestCharge
要求費用總計。 若要深入了解如何使用 Azure 入口網站和不同 SDK 來取得要求費用,請參閱尋找要求單位費用一文。
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);
}
取得查詢執行時間
您可以從查詢計量中擷取每個行程的查詢執行時間。 查看要求延遲時,請務必區分查詢執行時間與其他延遲來源,例如網路傳輸時間。 下列範例顯示如何取得每個來回行程的累計查詢執行時間:
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);
取得索引使用率
查看索引使用率可協助您偵錯緩慢的查詢。 傳回結果集之前,無法使用容器中所有文件完整掃描的索引結果的查詢。
以下是掃描查詢的範例:
SELECT VALUE c.description
FROM c
WHERE UPPER(c.description) = "BABYFOOD, DESSERT, FRUIT DESSERT, WITHOUT ASCORBIC ACID, JUNIOR"
此查詢的篩選條件使用未經索引處理的系統函數 UPPER。 針對大型集合執行此查詢時,第一次延續會產生下列查詢計量:
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
在查詢計量輸出中,請注意下列值:
Retrieved Document Count : 60,951
Retrieved Document Size : 399,998,938 bytes
此查詢載入 60,951 個文件,總計 399,998,938 個位元組。 載入如此多位元組導致很高的成本或要求單位費用。 執行此查詢也耗時甚久,從花費總時間屬性即可明白:
Total Query Execution Time : 4,500.34 milliseconds
表示執行查詢花 4.5 秒 (這只是一次延續)。
若要將此範例查詢最佳化,請避免在篩選條件中使用 UPPER。 相反地,在建立或更新文件時,必須以全部大寫字元插入 c.description
值。 於是查詢變成:
SELECT VALUE c.description
FROM c
WHERE c.description = "BABYFOOD, DESSERT, FRUIT DESSERT, WITHOUT ASCORBIC ACID, JUNIOR"
此查詢現在可以經過索引處理。 或者,您可以使用計算屬性來編製系統函數或複雜計算結果的索引,否則會導致完整掃描。
若要深入了解微調查詢效能,請參閱微調查詢效能一文。