احصل على مقاييس تنفيذ استعلام لغة الاستعلامات المركبة وتحليل أداء الاستعلام باستخدام عدة تطوير البرامج .NET

ينطبق على: NoSQL

توضح هذه المقالة كيفية ملف تعريف أداء استعلام SQL على Azure Cosmos DB باستخدام ServerSideCumulativeMetrics التي تم استردادها من .NET SDK. ServerSideCumulativeMetrics هو كائن مكتوب بقوة مع معلومات حول تنفيذ الاستعلام الخلفي. يحتوي على مقاييس تراكمية يتم تجميعها عبر جميع الأقسام المادية للطلب، وقائمة بالمقاييس لكل قسم فعلي، وإجمالي رسوم الطلب. تم توثيق هذه المقاييس بمزيد من التفاصيل في مقالة ضبط أداء الاستعلام .

الحصول على مقاييس الاستعلام

تتوفر مقاييس الاستعلام ككائن مكتوب بقوة في .NET SDK بدءا من الإصدار 3.36.0. قبل هذا الإصدار، أو إذا كنت تستخدم لغة SDK مختلفة، يمكنك استرداد مقاييس الاستعلام عن طريق تحليل Diagnostics. يوضح نموذج التعليمات البرمجية التالي كيفية الاسترداد ServerSideCumulativeMetrics من Diagnostics في 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();
}

يمكنك أيضا الحصول على مقاييس الاستعلام من FeedResponse استعلام LINQ باستخدام ToFeedIterator() الأسلوب :

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

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

المقاييس التراكمية

ServerSideCumulativeMetricsCumulativeMetrics يحتوي على خاصية تمثل مقاييس الاستعلام المجمعة على جميع الأقسام لرحلة واحدة ذهابا وإيابا.

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

المقاييس المقسمة

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

الحصول على رسوم طلب الاستعلام

يمكنك تسجيل وحدات الطلب التي يستهلكها كل استعلام للتحقيق في الاستعلامات أو الاستعلامات المكلفة التي تستهلك معدل نقل عالي. يمكنك الحصول على إجمالي رسوم الطلب باستخدام الخاصية TotalRequestCharge في ServerSideCumulativeMetrics أو يمكنك إلقاء نظرة على رسوم الطلب من كل قسم باستخدام الخاصية RequestCharge لكل ServerSidePartitionedMetrics مرة يتم إرجاعها.

تتوفر رسوم الطلب الإجمالية أيضا باستخدام الخاصية RequestCharge في FeedResponse. لمعرفة المزيد حول كيفية الحصول على رسوم الطلب باستخدام مدخل Microsoft Azure وعدة تطوير البرامج المختلفة، راجع واحصل على مقالة رسوم وحدة الطلب .

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"

يمكن الآن تقديم هذا الاستعلام من الفهرس. بدلا من ذلك، يمكنك استخدام الخصائص المحسوبة لفهرسة نتائج وظائف النظام أو العمليات الحسابية المعقدة التي قد تؤدي بخلاف ذلك إلى فحص كامل.

لمعرفة المزيد حول ضبط أداء الاستعلام، راجع مقالة ضبط أداء الاستعلام .

المراجع

الخطوات التالية