
直接用 LIMIT offset, size 做分页,在数据量大、页码靠后时会严重变慢——因为 MySQL 仍需扫描并跳过前 offset 行。真正高效的分页,核心是避免全表扫描跳过大量数据,改用基于有序索引的“游标分页”或“延迟关联”等策略。
用主键/唯一索引做游标分页(推荐)
适用于按主键(如 id)或带索引的时间字段(如 created_at)排序的场景。不再依赖 OFFSET,而是记录上一页最后一条的值,下一页查询从该值之后开始。
例如:查第 10001–10010 条(按 id 升序)
- 传统写法(低效):
SELECT * FROM orders ORDER BY id LIMIT 10000, 10 - 游标写法(高效):
SELECT * FROM orders WHERE id > 12345 ORDER BY id LIMIT 10(假设上一页最大id是 12345)
关键点:必须有对应字段的索引;排序字段不能有重复值(或组合唯一),否则需加额外条件去重;前端需保存并传递游标值(如 last_id=12345)。
延迟关联优化 OFFSET 分页(兼容旧逻辑)
当必须支持任意页码跳转(如用户手动输入页码)、且无法改造成游标分页时,可用“先查主键,再关联详情”的方式减少回表开销。
示例:
eSiteGroup站群管理系统是基于eFramework低代码开发平台构建,是一款高度灵活、可扩展的智能化站群管理解决方案,全面支持SQL Server、SQLite、MySQL、Oracle等主流数据库,适配企业级高并发、轻量级本地化、云端分布式等多种部署场景。通过可视化建模与模块化设计,系统可实现多站点的快速搭建、跨平台协同管理及数据智能分析,满足政府、企业、教育机构等组织对多站点统一管控的
- 低效:
SELECT id, name, amount FROM orders ORDER BY created_at DESC LIMIT 10000, 20 - 优化:
SELECT o.id, o.name, o.amount FROM orders o INNER JOIN (SELECT id FROM orders ORDER BY created_at DESC LIMIT 10000, 20) t ON o.id = t.id
原理:子查询只扫描索引(created_at + id 覆盖索引更佳),拿到 20 个 id 后,再通过主键快速回查完整行。比全字段排序跳过万行快得多。
避免深分页的业务设计建议
技术优化之外,很多“需要翻到 500 页”的需求本身值得质疑。
- 前端限制可跳转页码(如最多到第 100 页),超出后引导用户用搜索或筛选缩小范围
- 对列表增加时间范围、状态等强过滤条件,让默认分页始终落在热数据区间
- 后台导出功能单独处理,不走在线分页逻辑;高偏移量查询走异步任务+缓存结果
补充:覆盖索引与排序字段选择
无论用哪种方案,确保 ORDER BY 字段有索引,并尽可能让 WHERE + ORDER BY + SELECT 涉及的字段组成覆盖索引,避免回表。
例如查询 SELECT id, title, created_at FROM posts WHERE status = 1 ORDER BY created_at DESC LIMIT 20,理想索引是:INDEX(status, created_at, id, title)(注意字段顺序和方向)。
若排序字段类型不一致(如 varchar 列参与排序但未加 COLLATE),也可能导致索引失效,需检查 EXPLAIN 中的 key_len 和 Extra 字段。









