news 2026/4/23 12:40:08

SQL深度分页问题案例实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SQL深度分页问题案例实战

文章目录

  • 概述
    • 对比
    • 工作原理
    • 性能对比
      • 查询性能对比
      • 数据库负载对比
  • 代码示例
    • 传统分页示例
        • 请求
        • 响应
        • SQL执行
    • 游标分页示例
        • 首次请求(无游标)
        • 响应
        • 后续请求(使用游标)
        • SQL执行
    • 游标分页最佳实践
    • 总结
      • 选择建议

概述

对比

特性传统分页游标分页
定义使用 OFFSET 和 LIMIT 参数,通过跳过前面的记录来获取指定页的数据。使用一个游标(cursor)来标记当前位置,基于游标位置获取后续数据。
特点1. 需要知道总记录数(COUNT查询)
2. 使用页码(page)和每页数量(size)
3. 可以跳转到任意页面
1. 不需要总记录数
2. 使用游标(cursor)和每页数量(size)
3.只能顺序翻页,不能跳转
优点1. 可以跳转页面:用户可以直接跳转到第N页
2. 显示总数:可以显示总记录数和总页数
3. 实现简单:逻辑直观,易于理解
4. 兼容性好:所有数据库都支持OFFSETLIMIT
1.性能优秀:
+ 不需要COUNT(*)查询
+ 查询速度稳定,不受数据量影响
+ 使用索引高效定位
2.数据一致性:
+ 基于游标位置查询,不受数据变化影响
+ 不会出现重复或遗漏数据
3.资源消耗低:
+ 不需要统计总数
+ 查询效率高
缺点1.性能问题
+COUNT(*)查询在大数据量下很慢
+OFFSET越大,查询越慢(需要跳过更多记录)
2.数据一致性问题
+ 在翻页过程中,如果有数据新增或删除,可能导致:
- 重复数据(同一数据出现在两页)
- 遗漏数据(某些数据永远不会被看到)
1. 不能跳转页面:只能顺序翻页,不能直接跳转到第N页
2. 显示总数:无法显示总记录数和总页数
3. 实现复杂:需要处理游标编码/解码
4. 游标管理:需要确保游标的唯一性和稳定性
应用场景1.需要显示总数和总页数
+ 商品列表需要显示"共1000件商品"
+ 订单列表需要显示"共50页"
2.需要跳转页面
+ 用户可以输入页码跳转
+ 需要显示页码导航(1, 2, 3…)
3.数据量不大
+ 数据量在10万以内
+ 查询频率不高
4.管理后台
+ 管理员需要查看总数
+ 需要跳转到指定页面
1.大数据量场景
+ 数据量超过10万条
+ 需要高性能查询
2.移动端列表
+ 无限滚动加载
+ 不需要显示总数
3.实时性要求高
+ 数据频繁变化
+ 需要保证数据一致性
4.C端应用
+ 用户主要浏览最新数据
+ 不需要跳转到历史页面
5.时间线/动态流
+ 微博、朋友圈等时间线
+ 订单列表(按时间排序)

工作原理

-- 先查询总数SELECTCOUNT(*)FROMtrade_orderWHEREuser_id='xxx';-- 第一页(page=1, size=10)SELECT*FROMtrade_orderWHEREuser_id='xxx'ORDERBYcreate_timeDESCLIMIT10OFFSET0;-- 第二页(page=2, size=10)SELECT*FROMtrade_orderWHEREuser_id='xxx'ORDERBYcreate_timeDESCLIMIT10OFFSET10;

执行流程:

  1. 执行COUNT(*)查询获取总记录数
  2. 根据页码计算OFFSET = (page - 1) * size
  3. 执行主查询,跳过OFFSET条记录
  4. 返回当前页数据和总数
-- 第一页(无游标)SELECT*FROMtrade_orderWHEREuser_id='xxx'ORDERBYcreate_timeDESC,idDESCLIMIT11;-- 查询11条,用于判断是否有更多数据-- 第二页(使用游标)SELECT*FROMtrade_orderWHEREuser_id='xxx'AND(create_time<'2025-12-16 10:00:00'OR(create_time='2025-12-16 10:00:00'ANDid<'xxx-uuid'))ORDERBYcreate_timeDESC,idDESCLIMIT11;

执行流程:

  1. 如果有游标,解码游标获取createTimeid
  2. 添加游标条件:create_time < cursor.createTime OR (create_time = cursor.createTime AND id < cursor.id)
  3. 查询size + 1条数据(多查1条用于判断是否有更多数据)
  4. 如果返回size + 1条,说明还有更多数据,返回前size条并生成下一个游标
  5. 如果返回 ≤size条,说明没有更多数据

性能对比

查询性能对比

说明:

  • 传统分页的COUNT(*)查询时间随数据量线性增长
  • 传统分页的OFFSET越大,查询越慢
  • 游标分页性能稳定,不受数据量和页码影响

数据库负载对比

操作传统分页游标分页
每次查询SQL数量2条(COUNT + SELECT)1条(SELECT)
COUNT查询需要全表扫描或索引扫描不需要
OFFSET操作需要跳过N条记录不需要
索引利用部分利用完全利用

代码示例

传统分页示例

请求
POST /api-portal/trade/order/page { "page": 2, "size": 10, "status": 10, "createTime": ["2025-11-16 00:00:00", "2025-12-16 00:00:00"] }
响应
{ "code": 0, "data": { "list": [...], "total": 1000, "page": 2, "size": 10, "pages": 100 } }
SQL执行
-- 1. 查询总数 SELECT COUNT(*) FROM trade_order WHERE user_id = 'xxx' AND status = 10 AND create_time BETWEEN '2025-11-16' AND '2025-12-16'; -- 2. 查询数据 SELECT * FROM trade_order WHERE user_id = 'xxx' AND status = 10 AND create_time BETWEEN '2025-11-16' AND '2025-12-16' ORDER BY create_time DESC LIMIT 10 OFFSET 10;

游标分页示例

首次请求(无游标)
POST /api-portal/trade/order/cursor-page { "size": 10, "status": 10, "createTime": ["2025-11-16 00:00:00", "2025-12-16 00:00:00"] }
响应
{ "code": 0, "data": { "list": [...], "nextCursor": "MjAyNS0xMi0xNlQxMDowMDowMHw2ZTdhNTVlYi0zMzc0LTRjMDYtYmEzZi1mZGUwMmU5MGU5MWU=", "hasMore": true } }
后续请求(使用游标)
POST /api-portal/trade/order/cursor-page { "cursor": "MjAyNS0xMi0xNlQxMDowMDowMHw2ZTdhNTVlYi0zMzc0LTRjMDYtYmEzZi1mZGUwMmU5MGU5MWU=", "size": 10, "status": 10, "createTime": ["2025-11-16 00:00:00", "2025-12-16 00:00:00"] }
SQL执行
-- 查询 size + 1 条数据 SELECT * FROM trade_order WHERE user_id = 'xxx' AND status = 10 AND create_time BETWEEN '2025-11-16' AND '2025-12-16' AND (create_time < '2025-12-16 10:00:00' OR (create_time = '2025-12-16 10:00:00' AND id < 'xxx-uuid')) ORDER BY create_time DESC, id DESC LIMIT 11;

⚠️需要注意的问题:

  1. 游标设计
  • 游标必须唯一且稳定(使用createTime + id组合)
  • 游标字段必须有索引
  • 使用 Base64 编码保护游标
  1. 排序字段
  • 必须使用唯一字段作为排序依据(如id
  • 避免使用可能重复的字段(如createTime单独排序)
  1. 游标失效
  • 如果数据被删除,游标可能失效
  • 需要处理游标解析失败的情况
  1. 关键字查询
  • JOIN 查询时需要注意性能
  • 使用DISTINCT去重

游标分页最佳实践

推荐做法:

  1. 游标格式
// 使用 createTime|id 格式,Base64编码 cursor = Base64.encode("2025-12-16T10:00:00|uuid-string")
  1. 排序规则
ORDER BY create_time DESC, id DESC -- 确保排序的唯一性和稳定性
  1. 游标条件
WHERE (create_time < cursor.createTime OR (create_time = cursor.createTime AND id < cursor.id))
  1. 判断是否有更多数据
// 查询 size + 1 条 List<Order> orders = query(size + 1); boolean hasMore = orders.size() > size; if (hasMore) { orders = orders.subList(0, size); nextCursor = createCursor(orders.get(size - 1)); }

总结

选择建议

场景推荐方案原因
移动端列表(无限滚动)游标分页性能好,数据一致
管理后台(需要总数)传统分页需要显示总数和跳转
大数据量(>10万)游标分页性能优势明显
小数据量(<10万)传统分页实现简单
实时数据流游标分页数据一致性好
需要跳转页面传统分页游标分页不支持
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 11:47:39

VSCode远程开发调试GPT-SoVITS模型技巧

VSCode远程开发调试GPT-SoVITS模型技巧 在语音合成技术飞速发展的今天&#xff0c;个性化音色克隆正从实验室走向消费级应用。只需一段一分钟的录音&#xff0c;就能复刻一个人的声音特征——这不再是科幻情节&#xff0c;而是 GPT-SoVITS 这类开源模型已经实现的能力。然而&am…

作者头像 李华
网站建设 2026/4/23 11:45:39

Excalidraw GPU算力加持!AI绘图速度提升10倍

Excalidraw GPU算力加持&#xff01;AI绘图速度提升10倍 在远程协作成为常态的今天&#xff0c;团队对可视化工具的需求早已超越了简单的“画框连线”。无论是产品原型讨论、系统架构设计&#xff0c;还是敏捷开发中的白板会议&#xff0c;一张清晰直观的草图往往比千言万语更高…

作者头像 李华
网站建设 2026/4/23 12:24:57

HuggingFace镜像网站推荐列表(国内可用)

HuggingFace镜像网站推荐列表&#xff08;国内可用&#xff09; 在深度学习项目开发中&#xff0c;模型下载速度往往成为制约效率的关键瓶颈。尤其是当团队位于国内&#xff0c;而依赖的预训练模型托管在 Hugging Face 官方服务器时&#xff0c;动辄几十分钟的等待、频繁断连重…

作者头像 李华
网站建设 2026/4/18 8:23:35

Docker镜像源不稳定?更换为清华镜像站提升TensorFlow稳定性

Docker镜像源不稳定&#xff1f;更换为清华镜像站提升TensorFlow稳定性 在开发人工智能应用时&#xff0c;一个常见的“小问题”却可能带来巨大的时间损耗&#xff1a;拉取 TensorFlow 容器镜像时网络卡顿、连接超时&#xff0c;甚至直接失败。尤其是在国内使用 Docker 默认源…

作者头像 李华
网站建设 2026/4/18 4:52:36

Windows下Python安装失败?换用清华源重试TensorFlow安装

Windows下Python安装失败&#xff1f;换用清华源重试TensorFlow安装 在搭建深度学习开发环境时&#xff0c;不少开发者都遇到过这样的场景&#xff1a;刚配好Python&#xff0c;信心满满地打开命令行输入pip install tensorflow&#xff0c;结果下载进度条卡在某个.whl文件上&a…

作者头像 李华
网站建设 2026/4/21 16:37:33

Mamba: Linear-Time Sequence Modeling with Selective State Spaces难点阅读

Mamba论文学习记录 Title&#xff1a;Mamba: Linear-Time Sequence Modeling with Selective State Spaces关于这段&#xff0c;GPT的解读如下&#xff08;借助AI解读&#xff0c;自行甄别是否妥当&#xff09;&#xff1a;GPT举了一个例子来说明&#xff0c;直观地感受公式怎么…

作者头像 李华