大表深分页优化:游标分页 vs limit offset

郑

郑后端

· 阅读 1958

分享

类似 limit 1000000, 20 的深分页会越翻越慢,因为数据库要扫描并丢弃前面的一百万行。

围绕「大表深分页优化:游标分页 vs limit offset」,很多讨论集中在技巧层面,但MySQL 与 RDS 性能治理的核心其实是工程纪律:备份是否可恢复、变更是否可回滚、容量是否可预估。把这三件事做扎实,绝大多数故障都可以避免或快速收敛。

大表深分页优化:游标分页 vs limit offset

为什么慢

offset 越大,MySQL 需要扫描 offset + limit 行再丢弃前 offset 行,代价随页数线性上升。

游标 / 键集分页(推荐)

用"上一页最后一条的有序 id(或时间戳)"作为游标条件,只扫描真正需要的那几行,走索引,性能恒定。

-- 慢:offset 越大越慢
SELECT * FROM orders ORDER BY id LIMIT 1000000, 20;

-- 快:游标分页,只扫 20 行
SELECT * FROM orders WHERE id > 1000000 ORDER BY id LIMIT 20;

延迟关联

必须用 offset 时,先用覆盖索引只取主键,再回表 join 明细,减少回表开销。

产品层规避

用"下一页 / 上一页"替代大跨度跳页;限制可翻页深度;提供按条件筛选,而不是让用户无限翻页。

小结:能用游标就别用大 offset,从 SQL 和产品交互两端一起治理深分页。

大表深分页优化:游标分页 vs limit offset 大表深分页优化:游标分页 vs limit offset

游标分页的代价在产品侧,要提前和业务对齐

技术上游标分页几乎总是更优,但它改变了交互能力:不能再直接跳到很后面的页码,总页数也可能变得不准确。这些限制如果不提前和产品、业务方沟通,改造到一半就会被要求回退。

  • 排序键要唯一且稳定:游标依赖一个单调、不重复的排序字段。若按时间排序且时间可能重复,需要用时间与主键组成复合游标,否则翻页时会出现漏条或重复。
  • 接口契约要变:请求参数从页码改为上一页返回的游标,响应里带上下一页游标与是否还有更多数据;旧接口应保留一段时间并限制最大可翻页深度,给调用方留出改造窗口。
  • 总条数另行处理:精确计数在大表上同样昂贵,可以用近似值、缓存结果,或者只在筛选条件变化时计算一次,不要每次翻页都重算。
  • 复杂检索交给检索服务:需要多条件组合、模糊匹配与聚合排序的列表,更适合走专门的检索服务,数据库只承担精确查询与写入。

改造顺序建议从访问最深的列表页开始:先用日志统计各接口的分页深度分布,把优化投入花在真正被翻到深处的场景上,其余页面维持现状即可。这样既能快速看到收益,也能避免一次性改动过多接口带来的回归风险。

MySQL 与 RDS 性能治理的三个基本盘

其一是可恢复性:备份的价值不在于「做了」,而在于「能恢复」,定期演练恢复流程比增加备份份数更重要。其二是可回滚性:任何结构或参数变更都应有回退路径,避免把生产当试验场。其三是可预估性:容量与增长趋势要有数据支撑,而不是等到告警才响应。

这三个基本盘稳固之后,再去做性能调优和架构升级,风险会小很多。

从排查到预防:把经验沉淀为机制

  • 慢的问题先定位再动手:用执行计划与监控数据说话,避免凭感觉改索引、改参数。
  • 变更留痕:每一次调整记录原因与预期,便于复盘与回退。
  • 容量预警前置:为存储、连接数、内存等关键水位设置提前量告警。
  • 演练常态化:把恢复演练、切换演练纳入日常,而不是出事才第一次做。

机制化的沉淀,能让MySQL 与 RDS 性能治理从「个人经验」变成「团队能力」。

#分页优化#MySQL#性能