Skip to content
MySQL 建模与查询优化 · 第 4 篇 / 共 6 篇
领域数据与中间件
专题MySQL 专题
当前序列MySQL 建模与查询优化
阅读位置第 4 篇 / 共 6 篇当前专题第 1 个序列 / 共 7 个序列

MySQL 分页优化:为什么 limit 越翻越慢,游标分页和覆盖索引怎么用

分页查询一开始通常都很好写:

sql
select * from table order by id limit 0, 20;

但页数一深,问题就来了:

  • 第 1 页很快
  • 第 1000 页开始明显变慢

这不是 MySQL “突然不行了”,而是分页方式本身的成本在放大。

先说结论

深分页慢的根本原因通常是:

  • MySQL 需要先扫描并跳过大量前置记录

常见优化方向有三种:

  • 覆盖索引 + 回表优化
  • 延迟关联
  • 基于游标 / 上次位置的翻页

一、为什么 limit offset, size 会越来越慢

例如:

sql
limit 100000, 20

这并不是“直接跳到第 100001 条”,而通常意味着:

  • 先定位并扫描前面大量记录
  • 再返回后面的 20 条

如果排序和过滤成本本来就不小,深分页会非常吃亏。

二、什么场景尤其容易慢

1. 大偏移量

页码越深,扫描和跳过的成本越高。

2. 还带复杂排序

如果排序字段没设计好索引,代价会进一步放大。

3. 一次查很多列

回表和数据传输成本也会叠加。

三、覆盖索引为什么是优化重点

如果分页先只查索引里能拿到的列,例如主键:

sql
select id from table where ... order by create_time limit 100000, 20;

然后再根据这批 id 回表拿完整数据,往往会更划算。

因为第一页扫描阶段可以尽量走:

  • 更轻的索引访问路径

四、延迟关联怎么理解

一种常见思路是:

  1. 先用索引查出当前页主键集合
  2. 再和主表关联拿完整数据

这本质上是在避免:

  • 一开始就对大结果集做重回表

五、游标分页什么时候更合适

如果产品场景不需要“任意跳到第 N 页”,而更像:

  • 下一页
  • 再下一页

那么可以考虑基于上一次最后一条记录做翻页,例如:

sql
where id > last_id order by id limit 20

这种方式最大的优点是:

  • 不需要跳过大量历史记录

特别适合

  • 时间线
  • 消息流
  • 后台滚动列表

六、分页优化更实用的思考顺序

1. 这个场景真的需要深分页吗

很多业务其实不需要允许用户跳到非常深的页数。

2. 排序字段有没有合适索引

如果没有,先做这一层。

3. 能不能拆成“先轻查主键,再回表”

这通常是很实用的优化。

4. 能不能改成游标式翻页

如果业务允许,这是更稳的方向。

一句话总结

MySQL 分页慢,不是 limit 语法的问题,而是深分页会天然放大扫描和跳过成本。

如果你能从“是否真的需要深分页、能否走覆盖索引、能否改成游标分页”这三层去优化,效果通常会比单纯调参数更直接。

延伸阅读相关文章优先当前专题,再补跨专题关联。
同一序列 · 顺着当前主线继续读SQL 开窗函数入门适合先把字段设计、索引、Explain、分页和慢 SQL 这条主线走顺。MySQL 专题 · MySQL 建模与查询优化同一序列 · 顺着当前主线继续读MySQL 慢 SQL 优化案例适合先把字段设计、索引、Explain、分页和慢 SQL 这条主线走顺。MySQL 专题 · MySQL 建模与查询优化同专题其他序列 · MySQL 变更与运维治理大表在线 DDL 怎么做更稳适合把计数、日志、在线变更和归档清理放在一起看。MySQL 专题 · MySQL 变更与运维治理同专题其他序列 · MySQL 变更治理与数据生命周期大事务为什么会拖垮数据库适合把大事务、DDL、回填、慢 SQL 治理和归档分层放进一条持续治理主线上看。MySQL 专题 · MySQL 变更治理与数据生命周期跨专题关联 · 同场景:基础学习@Conditional 系列注解怎么配合使用适合把自动装配、条件装配、Profile 和循环依赖放回 Spring Boot 启动过程里理解。Spring 专题 · Spring Boot 启动、装配与配置跨专题关联 · 同场景:基础学习保留策略和日志压缩适合哪些场景适合把副本机制、acks、批量压缩和日志组织放在一条 Kafka 投递主线上理解。Kafka 专题 · Kafka 投递链路与日志存储机制
继续阅读MySQL 建模与查询优化当前序列第 4 篇 / 共 6 篇当前专题第 1 个序列 / 共 7 个序列
往前看
上一篇MySQL Explain 实战回到当前序列上一章上一序列设计模式与结构抽象从第 1 篇开始:设计模式总览
往后看
下一篇SQL 开窗函数入门继续当前序列下一章下一序列MySQL 事务、锁与高可用从第 1 篇开始:MySQL 事务与锁

把零散经验整理成可查、可复用、可持续更新的企业级知识门户