我正在使用 .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 个条目):
CompanyName, WorkflowName, StartedAt
WorkflowName, StartedAt
因此,将其包含在复合索引中似乎(至少)改进了这个查询。
所以我的问题是,在执行已通过
ORDER BY
指定分区键的查询时,我是否始终必须为 QueryRequestOptions
子句提供分区键(因此也将其添加到复合索引中)?
在执行已通过
指定分区键的查询时,我是否始终必须为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