如何在一次(或最少)数据库访问中从 CosmosDB 跨分区查询获取所有项目?

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

我试图在单个查询中从多个特定分区返回多个文档,但是我发现该查询会为每个分区执行额外的数据库行程。

这是发送到 cosmos db 以从 3 个分区获取数据的查询(

AltairCode
是 PartitionKey):

select c.AltairCode, c.ReportedDate, c.UpdatedDate, c.TimesheetStatus, c.DurationValue, c.DurationPercentageValue from c 
where (not is_defined(c.IsDeleted) or c.IsDeleted = false) and 
((c.AltairCode = '10128003' and c.ReportedDate >= '2023-12-01') or --returns 4 documents
(c.AltairCode = '10125130' and c.ReportedDate >= '2023-11-01') or --returns 9 documents
(c.AltairCode = '10127661' and c.ReportedDate >= '2023-06-01')) --returns 5 documents

这是执行查询的 .Net 代码(为了方便起见,我对此查询进行了硬编码)

public async Task<CosmosResultsResponseMessage<T>> QueryItems<T>(string sql, List<(string name, object value)> parameters = null)
{
    var container = _cosmosClient.GetContainer(_databaseName, _containerName);

    sql = "select c.AltairCode, c.ReportedDate, c.UpdatedDate, c.TimesheetStatus, c.DurationValue, c.DurationPercentageValue from c where (not is_defined(c.IsDeleted) or c.IsDeleted = false) and ((c.AltairCode = '10128003' and c.ReportedDate >= '2023-12-01') or (c.AltairCode = '10125130' and c.ReportedDate >= '2023-11-01') or (c.AltairCode = '10127661' and c.ReportedDate >= '2023-06-01'))";
    QueryDefinition query = new QueryDefinition(sql);

    var allItems = new List<T>();
    var result = new CosmosResultsResponseMessage<T>();
    
    using (var streamResultSet = container.GetItemQueryStreamIterator(query))
    {
        while (streamResultSet.HasMoreResults)
        {
            using (var responseMessage = await streamResultSet.ReadNextAsync())
            {
                result.IsSuccessStatusCode = responseMessage.IsSuccessStatusCode;
                result.StatusCode = responseMessage.StatusCode;
                result.ErrorMessage = responseMessage.ErrorMessage;

                if (responseMessage.IsSuccessStatusCode)
                {
                    var streamResponse = FromStream<dynamic>(responseMessage.Content);
                    List<T> items = streamResponse.Documents.ToObject<List<T>>();
                    allItems.AddRange(items);
                }
                else
                {
                    break;
                }
            }
        }
    }

    result.ResultItems = allItems;
    return result;
}

我发现这段代码访问数据库3次而不是1,只是为了返回18文档,在

streamResultSet.ReadNextAsync()
行发生了3次数据库访问(并且
streamResultSet.HasMoreResults
返回
true
3次) ).

如何强制它只访问数据库一次? 或者也许还有另一种方法可以在一次访问数据库中从多个分区获取数据?

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

参考资料:

Cosmos DB 中的物理分区是独立的机器集,每个物理分区都有一个副本集,提供高可用性。

从连接的角度来看,因为这些是不同的机器,所以它们有不同的端点。

不可能对多个端点执行单个网络请求,这并不是 Cosmos DB 所特有的,但一般来说,如果需要连接到不同的端点,则它们需要是不同的请求。

在跨分区查询中,根据定义,查询需要转到不同的分区。如果需要去不同的Partition,那么唯一的办法就是向每个Partition发出请求,因为每个Partition有不同的端点。

如果这是一个单分区查询,那么它将是 1 个连接,但即使在这种情况下,您可能需要超过 1 个请求,这取决于数据量(不仅仅是文档),并且取决于数据的类型查询和可用的 RU。更多详细信息请参阅https://learn.microsoft.com/azure/cosmos-db/nosql/query/pagination

所以,简单的回答是,没有办法保证查询的所有数据总是在单个连接/网络请求中返回。在某些情况下可能会(单分区查询、无 RU 限制、响应低于 4Mb),但不能保证。

© www.soinside.com 2019 - 2024. All rights reserved.