mysql深度分页的几种解决方案
作者:青秋.
MySQL深分页需避免OFFSET,改用WHERE条件定位起点,常用游标分页、延迟关联或覆盖索引优化,结合缓存可提升性能,本文主要介绍了mysql深度分页的几种解决方案,感兴趣的可以了解一下
MySQL 解决深度分页(Deep Pagination)的核心思想是“丢掉 OFFSET,用条件定位起点”,从而避免大偏移量带来的全表扫描和大量回表。常见优化方案如下:
游标/范围分页(推荐)
原理:记住上一页最后一条记录的主键(或排序列),作为下一页的起始条件。
示例:
-- 上一页最后一条 id = 100000 SELECT * FROM t_order WHERE id > 100000 -- 无 OFFSET ORDER BY id LIMIT 10;
- 优点:直接跳到100000,性能稳定,不随页码增大而衰减;千万级数据仍可毫秒级返回。
- 缺点:只能顺序翻页,不能随机跳页;需要排序列唯一且连续。
延迟关联(JOIN 子查询)
原理:先用覆盖索引在子查询里拿到主键,再回表取完整行,减少大 OFFSET 的回表量。
示例:
SELECT t1.* FROM t_order t1 JOIN (SELECT id FROM t_order WHERE create_time > '2023-01-01' ORDER BY create_time LIMIT 4500000, 10) t2 ON t1.id = t2.id;
- 优点:比直接
LIMIT 4500000,10
(该方法先数4500000条数据,然后丢掉,)少读 450w 行数据。 - 注意:子查询里的列必须被索引覆盖,否则仍可能全表扫描。
覆盖索引 + 子查询定位起点
原理:先用覆盖索引查出第 N 条记录的排序列值,再用该值作为条件取后 10 条。
示例:
-- 1. 查出第 4500000 行的 create_time SELECT create_time FROM t_order ORDER BY create_time LIMIT 4500000, 1; -- 2. 用该 create_time 作为起点 SELECT * FROM t_order WHERE create_time >= <上一步的值> ORDER BY create_time LIMIT 10;
- 优点:避免大 OFFSET;支持非主键排序。
- 注意:排序列必须有索引,否则第 1 步也会很慢。
预计算或缓存
- 静态数据可提前算好页码结果,放入 Redis 或 ES,彻底避开 MySQL。
- 动态数据可用异步任务把每页首条主键写入缓存,查询时直接
>
条件。
为什么深分页不建议用 limit offset,size
SELECT * FROM t_order LIMIT 4500000, 10;
- MySQL 仍需扫描450万行然后扔掉,再取 10 行,耗时随 offset 线性增长。
- 高并发下容易造成 CPU、IO、内存暴涨,甚至 OOM。
一句话总结:“深分页不用 OFFSET,用条件(where)定位起点” 是所有优化手段的核心。
到此这篇关于mysql深度分页的几种解决方案的文章就介绍到这了,更多相关MySQL深度分页内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!