Mendapatkan metrik eksekusi kueri SQL dan menganalisis kinerja kueri menggunakan .NET SDK

BERLAKU UNTUK: NoSQL

Artikel ini menyajikan cara membuat profil performa kueri SQL di Azure Cosmos DB menggunakan ServerSideCumulativeMetrics yang diambil dari .NET SDK. ServerSideCumulativeMetrics adalah objek yang sangat diketik dengan informasi tentang eksekusi kueri backend. Ini berisi metrik kumulatif yang dikumpulkan di semua partisi fisik untuk permintaan, daftar metrik untuk setiap partisi fisik, dan total biaya permintaan. Metrik ini didokumentasikan secara lebih mendetail dalam artikel Menyelaraskan Kinerja Kueri.

Dapatkan kueri metrik

Metrik kueri tersedia sebagai objek yang ditik dengan kuat di .NET SDK yang dimulai pada versi 3.36.0. Sebelum versi ini, atau jika Anda menggunakan bahasa SDK yang berbeda, Anda dapat mengambil metrik kueri dengan mengurai Diagnostics. Sampel kode berikut menunjukkan cara mengambil ServerSideCumulativeMetrics dari Diagnostics dalam FeedResponse:

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();
}

Anda juga bisa mendapatkan metrik kueri dari FeedResponse kueri LINQ menggunakan metode :ToFeedIterator()

FeedIterator<MyClass> feedIterator = container.GetItemLinqQueryable<MyClass>()
    .Take(5)
    .ToFeedIterator();

while (feedIterator.HasMoreResults)
{
    FeedResponse<MyClass> feedResponse = await feedIterator.ReadNextAsync();
    ServerSideCumulativeMetrics metrics = feedResponse.Diagnostics.GetQueryMetrics();
}

Metrik Kumulatif

ServerSideCumulativeMetricsCumulativeMetrics berisi properti yang mewakili metrik kueri yang dikumpulkan di semua partisi untuk satu perjalanan pulang pergi.

// 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;

Anda juga dapat mengagregasi metrik ini di semua perjalanan pulang pergi untuk kueri. Berikut ini adalah contoh cara mengagregasi waktu eksekusi kueri di semua perjalanan pulang pergi untuk kueri tertentu menggunakan 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(response.Diagnostics.GetQueryMetrics());
}

// Aggregate values across trips for metrics of interest
TimeSpan totalTripsExecutionTime = metrics.Aggregate(TimeSpan.Zero, (currentSum, next) => currentSum + next.CumulativeMetrics.TotalTime);
DoSomeLogging(totalTripsExecutionTime);

Metrik Yang Dipartisi

ServerSideCumulativeMetricsPartitionedMetrics berisi properti yang merupakan daftar metrik per partisi untuk perjalanan pulang pergi. Jika beberapa partisi fisik tercapai dalam satu perjalanan pulang pergi, maka metrik untuk masing-masing partisi muncul dalam daftar. Metrik yang dipartisi direpresentasikan sebagai ServerSidePartitionedMetrics dengan pengidentifikasi unik untuk setiap partisi fisik dan biaya permintaan untuk partisi tersebut.

// 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;

Saat diakumulasikan di semua perjalanan pulang pergi, metrik per partisi memungkinkan Anda untuk melihat apakah partisi tertentu menyebabkan masalah performa jika dibandingkan dengan yang lain. Berikut ini adalah contoh cara mengelompokkan metrik partisi untuk setiap perjalanan menggunakan 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(response.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();
    }
}

Mendapatkan biaya permintaan kueri

Anda dapat mencatat unit permintaan yang digunakan oleh setiap kueri untuk menyelidiki kueri mahal atau kueri yang menggunakan throughput tinggi. Anda bisa mendapatkan total biaya permintaan menggunakan TotalRequestCharge properti di ServerSideCumulativeMetrics atau Anda dapat melihat biaya permintaan dari setiap partisi menggunakan RequestCharge properti untuk setiap ServerSidePartitionedMetrics yang dikembalikan.

Total biaya permintaan juga tersedia menggunakan RequestCharge properti di FeedResponse. Untuk mempelajari selengkapnya tentang cara mendapatkan biaya permintaan menggunakan portal Azure dan SDK lain, lihat artikel menemukan biaya unit permintaan.

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);
}

Mendapatkan waktu eksekusi kueri

Anda dapat mengambil waktu eksekusi kueri untuk setiap perjalanan dari metrik kueri. Saat melihat latensi permintaan, penting untuk membedakan waktu eksekusi kueri dari sumber latensi lain, seperti waktu transit jaringan. Contoh berikut menunjukkan cara mendapatkan waktu eksekusi kueri kumulatif untuk setiap perjalanan pulang pergi:

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);

Mendapatkan pemanfaatan indeks

Melihat pemanfaatan indeks dapat membantu Anda men-debug kueri lambat. Kueri yang tidak dapat menggunakan indeks menghasilkan pemindaian penuh semua dokumen dalam kontainer sebelum mengembalikan tataan hasil.

Berikut adalah contoh kueri pemindaian:

SELECT VALUE c.description 
FROM   c 
WHERE UPPER(c.description) = "BABYFOOD, DESSERT, FRUIT DESSERT, WITHOUT ASCORBIC ACID, JUNIOR"

Filter kueri ini menggunakan fungsi sistem UPPER, yang tidak disajikan dari indeks. Eksekusi kueri ini terhadap kumpulan besar menghasilkan metrik kueri berikut untuk kelanjutan pertama:

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

Perhatikan nilai berikut dari output metrik kueri:

Retrieved Document Count                 :          60,951
Retrieved Document Size                  :     399,998,938 bytes

Kueri ini memuat 60.951 dokumen, yang berjumlah 399.998.938 byte. Pemuatan byte sebanyak ini menghasilkan biaya tinggi atau biaya unit permintaan. Diperlukan juga waktu yang lama untuk menjalankan kueri, yang jelas dengan total waktu yang dihabiskan properti:

Total Query Execution Time               :        4,500.34 milliseconds

Artinya kueri membutuhkan waktu 4,5 detik untuk berjalan (dan ini hanya satu kelanjutan).

Untuk mengoptimalkan kueri contoh ini, hindari penggunaan UPPER dalam filter. Sebagai gantinya, ketika dokumen dibuat atau diperbarui, nilai c.description harus disisipkan dalam karakter huruf besar seluruhnya. Kueri kemudian menjadi:

SELECT VALUE c.description 
FROM   c 
WHERE c.description = "BABYFOOD, DESSERT, FRUIT DESSERT, WITHOUT ASCORBIC ACID, JUNIOR"

Kueri ini kini dapat dilayani dari indeks. Atau, Anda dapat menggunakan properti komputasi untuk mengindeks hasil fungsi sistem atau perhitungan kompleks yang jika tidak akan menghasilkan pemindaian penuh.

Untuk mempelajari selengkapnya tentang penyelarasan kinerja kueri, lihat artikel Menyelaraskan Kinerja Kueri.

Referensi

Langkah berikutnya