问题现象:select * from table limit 100000,10
跳过10万行再取10条。mysql需要扫描并丢弃前面100000条数据,偏移量越大,性能越差。
方案1:主键索引优化(最常用,推荐)
利用主键有序,避免大offset跳过数据
-- 低效深度分页 select * from user limit 100000,10; -- 优化:记住上一页最大id,where条件过滤 select * from user where id > 100000 limit 10;
✅优点:走主键索引,速度很快
❌缺点:
- 不适合id有删除、断号;
- 不能支持跳页(只能上一页、下一页,类似app滚动翻页),不能直接跳到第1000页。
方案2:子查询延迟关联
先通过索引拿到主键,再回表查询完整数据,减少回表开销
select u.* from user u inner join (select id from user limit 100000,10) t on u.id = t.id;
原理:子查询只扫描索引,不需要读取整行,拿到id之后再关联查完整记录。
适合业务需要支持跳页,又不能用id>xxx的场景。
方案3:覆盖索引
如果查询字段全部在索引里,不需要回表,深度分页压力会小很多。
-- name,phone建立联合索引 select id,name,phone from user limit 100000,10;
方案4:业务层面限制(互联网优先)
- 禁止前端直接跳转到几万页,只提供上一页、下一页;
- 大数据列表,不使用offset分页,使用游标分页(传最后一条id/时间戳);
- 导出大量数据不要用limit分页,使用流式读取。
方案5:使用时间戳做游标(非自增主键场景)
如果没有连续自增id,可以用创建时间作为游标
select * from user where create_time < '2026‑08‑20 12:00:00' order by create_time desc limit 10;
注意:排序字段必须建立索引。
不推荐的做法
limit offset,sizeoffset很大,性能暴跌;select count(*) from table统计总条数,大表count很慢,前端不要展示总页数。
补充:为什么limit offset,size慢?
innodb执行limit 100000,10,会从索引读取100010行,前100000行全部丢弃,只返回后10条。offset越大,扫描行数越多。
面试小结
- 如果是app滚动下拉:优先游标分页(id>上一页最大id),性能最好;
- 如果必须支持跳页:用延迟关联子查询;
- 大表尽量避免给前端展示总条数,放弃跳页功能;
- 排序字段务必建立索引,否则深度分页会更慢。
总结:
深度分页根源是大offset会扫描大量无效数据;优先游标分页记住上一页最后一条主键;需要跳页就用延迟关联;业务层面尽量不支持跳转到很深页码;大表避免count统计总数量。
以上就是mysql中深度分页问题的解决方案的详细内容,更多关于mysql深度分页问题的资料请关注代码网其它相关文章!
发表评论