面试知识库
进阶

大表分页优化#

一句话答案#

深分页 LIMIT offset 越大越慢,优化方案:游标分页(WHERE id > last_id)、子查询定位起始 id、延迟关联。

核心要点

问题: LIMIT offset, size offset 越大越慢(扫描 offset+size 行只取 size 行)

优化方案:

  1. 游标分页WHERE id > last_id LIMIT 10(推荐)
  2. 子查询定位:先通过覆盖索引子查询找到起始id
  3. 延迟关联JOIN (SELECT id FROM t LIMIT 1000000,10) tmp ON t.id=tmp.id
面试回答(2分钟版)

我来聊一下大表深分页的问题。MySQL 用 LIMIT offset, size 做分页时,offset 越大查询越慢,因为引擎需要扫描 offset+size 行然后丢掉前 offset 行,做了大量无效 IO。我在实际项目中主要用三种方案优化:第一种是游标分页,也就是 WHERE id > last_id LIMIT size,利用主键索引直接定位起始位置,适合”下一页”场景,性能最好;第二种是延迟关联,先用覆盖索引子查询拿到目标页的 id 列表,再 JOIN 回主表取完整字段,避免大量回表;第三种是子查询定位,思路类似但写法不同。选型上,Feed 流、瀑布流天然适合游标分页,后台管理系统需要跳页的就用延迟关联,同时前端也应该限制最大翻页深度来兜底。

追问与易错

追问方向:

  • “为什么 LIMIT offset 大时慢?”→ MySQL 执行 LIMIT offset, size 需要先扫描 offset+size 行再丢弃前 offset 行,offset 越大扫描的无效行越多,大量回表造成随机 IO 是性能瓶颈
  • “游标分页有什么限制?”→ 只能”下一页/上一页”顺序翻页,无法直接跳到任意页;要求排序字段有索引且值唯一(通常用主键 id);不适合后台管理需要跳页的场景
  • “ES 深分页怎么处理?”→ ES 默认 max_result_window=10000 限制深分页;替代方案用 search_after 游标分页(传入上一页最后一条的排序值),或 scroll API 做全量遍历(适合导出场景)

易错点:

  • ❌ 加索引就能解决深分页——不能解决 offset 扫描
  • ❌ 前端不限制最大页数