通过 QueryRequestOptions (Azure Cosmos DB) 提供分区键时是否必须在 ORDER BY 中包含分区键

问题描述 投票:0回答:1

我正在使用 .NET SDK 来执行涉及多个属性的

ORDER BY
的 Cosmos DB 查询,并且我定义了一个复合索引来优化这些查询。最近,我对 DAO 进行了更改,添加
QueryRequestOptions
来指定目标分区,并从
WHERE
子句中删除分区键。

这是我的代码示例(

CompanyName
是分区键):

string query = "SELECT * FROM w 
WHERE w.WorkflowName = @workflowName 
ORDER BY w.CompanyName DESC, w.WorkflowName DESC, w.StartedAt DESC";
var queryDefinition = new QueryDefinition(query).WithParameter("@workflowName", workflowName);
var options = new QueryRequestOptions { PartitionKey = new PartitionKey(pk) };
var entries = await _container.ExecuteQueryAsync<WorkflowRun>(queryDefinition, options).ConfigureAwait(false);

所以现在我想知道,既然我不再需要为

WHERE
子句提供分区键,我是否还必须为
ORDER BY
子句提供分区键?

因此我进行了快速测试(从单个分区读取 1000 个条目):

  • 12,27 RU,综合指数为
    CompanyName, WorkflowName, StartedAt
  • 13,48 RU,综合指数为
    WorkflowName, StartedAt

因此,将其包含在复合索引中似乎(至少)改进了这个查询。

所以我的问题是,在执行已通过

ORDER BY
指定分区键的查询时,我是否始终必须为
QueryRequestOptions
子句提供分区键(因此也将其添加到复合索引中)?

我已经自己解决了文档和来自.NET SDK的Github问题,但找不到具体的答案。

c# .net azure-cosmosdb
1个回答
0
投票

在执行已通过

ORDER BY
指定分区键的查询时,我是否始终必须为
QueryRequestOptions
子句提供分区键(因此也将其添加到复合索引中)?

执行已通过

QueryRequestOptions
提供分区键的查询时,通常不需要将其添加到复合索引或为
ORDER BY
子句提供分区键。

以下是我遵循的步骤:

  • 使用提供的

    cosmosEndpointUri
    cosmosPrimaryKey 创建 CosmosClient 实例。

  • 构建一个 SQL 查询,从容器中检索 customerId 与提供的值匹配的所有文档。

  • ORDER BY
    子句用于按orderDate降序对结果进行排序。

  • PartitionKey
    中指定
    QueryRequestOptions
    为了确保在所选分区内进行有效查询,这会指示 Cosmos DB 查询的目标分区。

  • container.GetItemQueryIterator
    创建一个迭代器来批量获取结果。

  • 使用

    ReadNextAsync
    循环查询结果,将检索到的订单添加到列表中。

  • 与给定的customerId匹配的订单包含在此列表中,该列表按id降序排列。

RU的消耗:

  • 2.83 RU,在 id 上有复合索引。

  • 2.82 RU,在 customerId 上有复合索引。

  • partition key
    上使用复合索引可以帮助最大限度地减少跨分区查询。

  • 它使您的查询在单个分区内快速运行,从而无需访问其他分区,这可能会更加消耗资源。

  • 有关综合指数的更多信息,请参阅此链接

下面是我尝试过的代码:

static async Task Main(string[] args)
{
    try
    {
        var cosmosClient = new CosmosClient(cosmosEndpointUri, cosmosPrimaryKey);
        var database = cosmosClient.GetDatabase(databaseId);
        var container = database.GetContainer(containerId);

        string customerId = "12345"; 
        string query = "SELECT * FROM c WHERE c.customerId = @customerId ORDER BY c.id DESC";
        
        var queryDefinition = new QueryDefinition(query).WithParameter("@customerId", customerId);
        var requestOptions = new QueryRequestOptions { PartitionKey = new PartitionKey(customerId) };
        var queryIterator = container.GetItemQueryIterator<Order>(queryDefinition, requestOptions: requestOptions);
        var orders = new List<Order>();

        while (queryIterator.HasMoreResults)
        {
            var response = await queryIterator.ReadNextAsync();
            orders.AddRange(response.Resource);
        }

        foreach (var order in orders)
        {
            Console.WriteLine($"Order ID: {order.Id}, Customer ID: {order.CustomerId}, Order Date: {order.OrderDate}");
        }
    }
    catch (Exception ex)
    {
        Console.Error.WriteLine($"Error: {ex.Message}");
    }
}

输出:

Order ID: 1, Customer ID: 12345, Order Date: 9/15/2023 2:30:00 PM
© www.soinside.com 2019 - 2024. All rights reserved.