Cosmos DB 的查询顾问

Cosmos DB 现在具有查询顾问,旨在帮助你使用 Cosmos DB 查询语言编写更快、更高效的查询。 无论是针对性能、成本还是可伸缩性进行优化,查询顾问都提供了可行的建议,帮助你充分利用 Azure 和 Microsoft Fabric 中的数据。

为什么查询优化很重要

Cosmos DB(在 Azure 和 Fabric 中)的查询语言非常灵活,开发人员可以使用熟悉的类似 SQL 的语法查询 JSON 数据。 随着应用程序的复杂性的增长,查询结构中的小差异可能会对性能和请求单位(RU)产生显著影响,尤其是在大规模情况下。

例如,返回相同结果的两个查询在效率上可能会因编写谓词的方式和索引的应用方式而产生巨大差异。

查询顾问会分析查询并提供有针对性的建议,以帮助你:

  • 通过识别低效的表达式或不必要的筛选器来降低 RU 成本
  • 通过更优化的查询结构提高查询性能
  • 了解每个建议背后的“原因”,并用明确的开发人员友好语言编写的说明。

工作原理

执行查询时,查询顾问会通过查询计划运行,评估可能导致高 RU 消耗、过度扫描或可能不必要的处理模式。 然后,它会返回一组建议,指示查询的哪个部分可能会限制性能,并建议可能有所帮助的潜在更改。

使用查询顾问

可以通过将属性设置为 来启用查询顾问功能。 如果未指定, PopulateQueryAdvice 则默认为 false. 若要访问建议,请使用字符串属性 FeedResponse.QueryAdvice

重要

查询顾问仅适用于适用于 Cosmos DB 的 .NET SDK。 查询建议也仅在第一次往返时返回。 建议在后续延续调用中不可用。

请考虑以下示例查询:

SELECT VALUE
    r.id
FROM
    root r
WHERE
    CONTAINS(r.name, 'Abc')

下面是执行此查询并使用查询顾问的 SDK 请求示例:

using Microsoft.Azure.Cosmos;

CosmosClient client = new("<connection-string>");
Container container = client.GetContainer("<database-name>", "<container-name>");

string query = """
SELECT VALUE
    r.id
FROM
    root r
WHERE
    CONTAINS(r.name, 'Abc')
""";

QueryRequestOptions requestOptions = new()
{
    PopulateQueryAdvice = true
};

using FeedIterator<dynamic> itemQuery = container.GetItemQueryIterator<dynamic>(
    query,
    requestOptions: requestOptions);

string? queryAdvice = null;
while (itemQuery.HasMoreResults)
{
    if (queryAdvice is not null)
    {
        break;
    }

    FeedResponse<dynamic> page = await itemQuery.ReadNextAsync();
    queryAdvice = page.QueryAdvice;
}

Console.WriteLine(queryAdvice);

此请求返回以下项 QA1002的单个建议语句:

QA1002: If you are matching on a string prefix, consider using STARTSWITH. [...]

查询建议包含三个重要信息:

  • 查询建议 IDQA1002
  • 建议说明:在此示例中, If you are matching on a string prefix, consider using STARTSWITH.
  • 文档链接:指向详细指南的 URL

注释

此示例中省略了指向文档的链接。

例子

请考虑使用查询顾问的方案的以下示例。

优化系统函数使用情况

请考虑使用函数的 GetCurrentTimestamp 此示例:

SELECT
    GetCurrentTicks() 
FROM
    container c
WHERE
    GetCurrentTimestamp() > 10

在此示例中,查询顾问返回两条建议: QA1008QA1009。 每条建议都分为字符串输出中的新行。

QA1009: Consider using GetCurrentTimestampStatic instead of GetCurrentTimestamp in the WHERE clause. [...]
QA1008: Consider using GetCurrentTicksStatic instead of GetCurrentTicks in the WHERE clause. [...]

使用此建议,可以将查询重写为以下替代方法:

SELECT
    GetCurrentTicksStatic() 
FROM
    container c
WHERE
    GetCurrentTimestampStatic() > 10