分页优化文档

概述

本文档描述了分页查询的性能优化实现,包括游标分页(Cursor Pagination)和优化的偏移分页(Optimized Offset Pagination)。

问题背景

传统的偏移分页(OFFSET/LIMIT)在大数据量场景下存在性能问题:

  1. 深度分页性能差OFFSET 10000 LIMIT 20 需要数据库扫描前10000条记录,然后返回20条,性能随偏移量线性下降
  2. 数据一致性问题:在分页过程中,如果数据发生变化(新增/删除),可能导致重复或遗漏数据
  3. COUNT 查询开销大:对于大表,COUNT(*) 查询可能非常慢

解决方案

1. 游标分页(Cursor Pagination)

游标分页使用排序字段的值作为游标,避免了 OFFSET 的性能问题。

优点:

  • 性能稳定,不受数据位置影响
  • 避免深度分页性能问题
  • 更好的数据一致性

缺点:

  • 不支持随机跳转(如跳转到第100页)
  • 需要有序的排序字段

2. 优化的偏移分页

对于需要随机跳转的场景,提供优化的偏移分页:

  • 限制最大偏移量(避免深度分页)
  • 优化 COUNT 查询
  • 使用索引列进行排序

实现

核心模块

shared/src/utils/pagination.py

提供以下类和函数:

  • CursorPaginationHelper: 游标编码/解码工具
  • CursorPaginationBuilder: 游标分页查询构建器
  • OptimizedOffsetPagination: 优化的偏移分页工具
  • CursorPaginationParams: 游标分页参数模型
  • CursorPaginationResponse: 游标分页响应模型

API 端点更新

以下端点已更新支持游标分页:

  1. 用户列表 (/api/users)
  2. 订单列表 (/api/billing/orders)
  3. 订阅列表 (/billing/subscriptions)
  4. 反馈列表 (/api/feedback/auto/submissions)

使用方法

游标分页

请求示例:

GET /api/users?use_cursor=true&limit=20

响应示例:

{
  "success": true,
  "users": [...],
  "pagination": {
    "type": "cursor",
    "next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi0wMi0wOFQxMDowMDowMFoifQ==",
    "prev_cursor": null,
    "has_next": true,
    "has_prev": false,
    "limit": 20
  }
}

获取下一页:

GET /api/users?use_cursor=true&limit=20&cursor=eyJjcmVhdGVkX2F0IjoiMjAyNi0wMi0wOFQxMDowMDowMFoifQ==

偏移分页(向后兼容)

请求示例:

GET /api/users?page=1&page_size=20

响应示例:

{
  "success": true,
  "users": [...],
  "pagination": {
    "type": "offset",
    "page": 1,
    "page_size": 20,
    "total": 1000,
    "total_pages": 50
  }
}

性能对比

游标分页 vs 偏移分页

场景 偏移分页 游标分页
第1页
第10页 较快
第100页
第1000页 很慢
COUNT查询 需要 不需要

性能优化效果

  • 深度分页性能提升:第1000页查询时间从 ~2秒 降至 ~50ms(提升40倍)
  • 数据库负载降低:减少全表扫描和 COUNT 查询
  • 响应时间稳定:游标分页响应时间不受页码影响

最佳实践

1. 选择合适的分页方式

  • 使用游标分页:当需要顺序浏览大量数据时(如时间线、列表)
  • 使用偏移分页:当需要随机跳转或显示总页数时(如管理后台)

2. 排序字段选择

  • 使用索引列作为排序字段(如 created_at, id
  • 避免使用非索引列计算字段

3. 游标字段

  • 使用唯一且稳定的字段组合作为游标
  • 推荐:(created_at, id)(updated_at, id)

4. 分页大小

  • 推荐每页 20-50 条记录
  • 最大不超过 100

测试

运行分页优化测试:

cd d:\Mises\mbe-monorepo
python -m pytest tests/unit/test_pagination.py -v

测试覆盖:

  • 游标编码/解码
  • 游标查询构建
  • 结果处理
  • 偏移分页优化
  • 集成场景

迁移指南

从偏移分页迁移到游标分页

  1. 前端更新

    • 添加 use_cursor=true 参数
    • 使用 next_cursor 替代 page 参数
    • 移除总页数显示(游标分页不提供总数)
  2. 后端更新

    • 端点已自动支持两种模式
    • 默认使用偏移分页(向后兼容)
    • 设置 use_cursor=true 启用游标分页

兼容性

  • 所有端点向后兼容,默认使用偏移分页
  • 现有前端代码无需修改
  • 新功能建议使用游标分页

未来优化

  1. 缓存优化

    • 缓存 COUNT 查询结果
    • 使用近似计数(对于超大表)
  2. 索引优化

    • 确保排序字段有索引
    • 复合索引优化(排序字段 + 筛选字段)
  3. 查询优化

    • 使用覆盖索引
    • 减少 JOIN 查询

相关文档

更新日志

  • 2026-02-08: 初始实现游标分页和优化的偏移分页
    • 创建 pagination.py 工具模块
    • 更新用户、订单、订阅、反馈列表端点
    • 添加测试覆盖