使用 Azure Cosmos DB Python SDK 获取 SQL 查询执行指标并分析查询性能

适用范围: NoSQL

本文介绍如何使用查询执行指标分析 Azure Cosmos DB 上的 SQL 查询性能。 它包含了跨请求的所有物理分区聚合的累积指标、每个物理分区的指标列表和请求总费用。 优化查询性能一文中更详细地阐述了这些指标。

启用查询指标

若要获取查询指标,需要在查询参数中将 populate_query_metrics 标志设置为 True,如下所示。 你可能还有兴趣启用索引指标进行调试,可以通过将 populate_query_metrics 标志设置为 True 来启用它:

results = container.query_items(
    query=queryText,
    enable_cross_partition_query=True,
    populate_index_metrics=True,
    populate_query_metrics=True
)

获取查询执行指标

在 Python SDK 中,可以从容器客户端读取 x-ms-documentdb-query-metrics 标头值来获取查询执行指标。 以下代码片段展示了如何读取查询执行指标:

results = container.query_items(
    query=queryText,
    enable_cross_partition_query=True,
    populate_query_metrics=True
)

items = [item for item in results]
'''
Please note that the last_response_headers are available only after the first iteration of the results as the query execution starts only when result iteration begins
'''
print("Query Metrics: ",container.client_connection.last_response_headers['x-ms-documentdb-query-metrics'])

结果将为你提供查询执行相关信息,如下所示:

totalExecutionTimeInMs=0.27;
queryCompileTimeInMs=0.04;
queryLogicalPlanBuildTimeInMs=0.00;
queryPhysicalPlanBuildTimeInMs=0.02;
queryOptimizationTimeInMs=0.00;
VMExecutionTimeInMs=0.02;
indexLookupTimeInMs=0.00;
instructionCount=17;
documentLoadTimeInMs=0.01;
systemFunctionExecuteTimeInMs=0.00;
userFunctionExecuteTimeInMs=0.00;
retrievedDocumentCount=3;
retrievedDocumentSize=1005;
outputDocumentCount=3;
outputDocumentSize=1056;
writeOutputTimeInMs=0.00;
indexUtilizationRatio=1.00

上述结果可以让你了解查询的效率。 可以查看 totalExecutionTimeInMs 来了解查询需要多长时间来执行。 indexUtilizationRatio 可以让你深入了解查询利用索引的情况。 若要详细了解这些指标,请参阅查询执行指标一文。

获取查询请求费用

可以捕获读取 x-ms-request-charge 值所消耗的请求单位 (RU) 总数。 无需显式设置任何参数即可检索请求费用值。 以下示例显示如何获取每次继续查询的请求费用:

items = [item for item in results]
print("Request Units consumed: ",container.client_connection.last_response_headers['x-ms-request-charge'])

获取索引利用率

查看索引利用率有助于对慢速查询进行调试。 好的索引利用率分数必须接近 1。 在返回结果集之前,无法使用索引的查询会导致对容器中的所有文档进行完全扫描。

下面是扫描查询的示例:

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"

现在,可以从索引为此查询提供服务。 或者,可以使用计算属性为系统函数或负载计算的结果编制索引(否则该结果将会导致完全扫描)。

若要查看潜在的索引建议并检查已利用哪些索引,必须将 populate_index_metrics 参数设置为 True,然后才能从容器客户端读取 x-ms-documentdb-index-utilization 标头值。 以下代码片段展示了如何读取索引利用率指标:

results = container.query_items(
    query=queryText,
    enable_cross_partition_query=True,
    populate_index_metrics = True
)
items = [item for item in results]
print("Index Utilization Info: ",container.client_connection.last_response_headers['x-ms-cosmos-index-utilization'])

若要详细了解如何优化查询性能,请参阅优化查询性能一文。

参考

后续步骤