azure-cosmosdb - 使用 OFFSET 和 LIMIT 的 Cosmos DB 分页性能

标签 azure-cosmosdb

我正在创建一个基于 Cosmos DB 和 ASP.NET Core 3.0 的 API。使用 Cosmos DB 4.0 预览版 1 .NET Core SDK。我使用 OFFSET 和 LIMIT 子句实现了分页。我看到 RU 费用显着增加,您访问的页数越高。页面大小为 100 个项目的示例:

Page 1: 9.78 RU
Page 10: 37.28 RU
Page 100: 312.22 RU
Page 500: 358.68 RU

查询很简单:

SELECT * from c OFFSET [page*size] LIMIT [size]

我做错了什么,还是这是预期的? OFFSET 是否需要扫描整个逻辑分区?我正在查询分区中大约有 10000 个项目的单个分区键。似乎分区中的项目越多,性能就越差。 (另见 uservoice 中“Russ”对此功能的评论)。

有没有更好的方法来实现整个分区的高效分页?

编辑 1:此外,我注意到在具有 10,000 个项目的分区中执行 OFFSET/LIMIT 时,在 Cosmos 模拟器中执行查询也会减慢 waaayyy。

编辑 2:这是我用于查询的存储库代码。本质上,它正在包装 Container.GetItemQueryStreamIterator() 方法并在处理 IAsyncEnumerable 时拉出 RU。查询本身就是上面的 SQL 字符串,没有 LINQ 或其他神秘之处。
public async Task<RepositoryPageResult<T>> GetPageAsync(int? page, int? pageSize, EntityFilters filters){

// Enforce default page and size if null
int validatedPage = GetValidatedPageNumber(page);
int validatedPageSize = GetValidatedPageSize(pageSize);

IAsyncEnumerable<Response> responseSet = cosmosService.Container.GetItemQueryStreamIterator(
    BuildQuery(validatedPage, validatedPageSize, filters),
    requestOptions: new QueryRequestOptions()
    {
        PartitionKey = new PartitionKey(ResolvePartitionKey())
    });

var pageResult = new RepositoryPageResult<T>(validatedPage, validatedPageSize);
await foreach (Response response in responseSet)
{
    LogResponse(response, COSMOS_REQUEST_TYPE_QUERY_ITEMS); // Read RU charge
    if (response.Status == STATUS_OK && response.ContentStream != null)
    {
        CosmosItemStreamQueryResultSet<T> responseContent = await response.ContentStream.FromJsonStreamAsync<CosmosItemStreamQueryResultSet<T>>();
        pageResult.Entities.AddRange(responseContent.Documents);
        foreach (var item in responseContent.Documents)
        {
            cache.Set(item.Id, item); // Add each item to cache
        }
    }
    else
    {
        // Unexpected status. Abort processing.
        return new RepositoryPageResult<T>(false, response.Status, message: "Unexpected response received while processing query response.");
    }
}

pageResult.Succeeded = true;
pageResult.StatusCode = STATUS_OK;
return pageResult;

}

编辑3:

从 cosmos.azure.com 运行相同的原始 SQL,我在查询统计中注意到:
OFFSET 0 LIMIT 100: Output document count = 100, Output document size = 44 KB
OFFSET 9900 LIMIT 100: Output document count = 10000, Output document size = 4.4 MB

事实上,检查浏览器中的网络选项卡会发现 100 个单独的 HTTP 查询,每个查询检索 100 个文档!所以 OFFSET 目前似乎不在数据库中,而是在客户端,它在丢弃前 99 个查询数据之前检索所有内容。这不可能是预期的设计?查询是不是应该告诉数据库在 1 个响应中总共只返回 100 个项目,而不是全部 10000 个,所以客户端可以扔掉 9900 个?

最佳答案

基于 code这将意味着客户端正在跳过文档,从而增加 RU。

我在浏览器(cosmos.azure.com,使用 JS SDK)上测试了相同的场景,行为是相同的,随着偏移量的移动,RU 增加。

Paging in cosmos.azure.com

Paging in cosmos.azure.com increasing OFFSET

关于azure-cosmosdb - 使用 OFFSET 和 LIMIT 的 Cosmos DB 分页性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58771772/

相关文章:

azure - 如何在 Cosmos DB 中查找逻辑分区数量和大小

c# - 如何在 Documentdb 中创建一个自动递增的列

asp.net - SQL Server、Cosmos/文档数据库、身份成员资格和多语言持久性

c# - documentdb 与 linq 连接

node.js - 无法连接到azure cosmos db中的Mongodb

azure - 如果 Azure Document DB 中的数据已加密,为什么我能够查看数据?

azure - 对于 CosmosDB 不区分大小写的查询 : use duplicate uppercased field or StringEquals?

c# - 从 .net 调用 DocumentDb 存储过程

azure - 如何在 Cosmos DB 中使用很长的复合索引?

node.js - DocumentDB 中的分页