深浅主题
深分页性能
问题现象
第一页很快,第几万页耗时明显增加;返回只有 20 行但扫描和回表数量巨大。
适用环境
MySQL 8、InnoDB;列表需要按 ID 或组合键向后浏览。
本文是可复用的排障示例,不代表某次个人生产事故。命令中的名称、账号和数据均为示例,执行前请替换为已确认的目标。
复现或诊断步骤
- 比较 LIMIT 0,20 与 LIMIT 200000,20 的扫描与延迟。
- 检查排序能否利用索引,确认过滤条件是否仍需要大量回表。
- 明确用户是否真的需要任意页跳转,还是只需上一页、下一页和导出。
原因分析
OFFSET 不能直接定位第 N 条满足条件的结果,数据库仍需读取并跳过前面的记录。宽行查询还会放大回表成本,索引只能缓解部分开销。
修复示例
sql
-- 使用上一页末行 ID,排序和过滤需一致
SELECT id, title
FROM article
WHERE id > :last_id AND status = 'PUBLISHED'
ORDER BY id
LIMIT 20;
-- 必须保留偏移跳转时,可先在窄索引中定位 ID
SELECT a.id, a.title
FROM article a
JOIN (
SELECT id FROM article
WHERE status = 'PUBLISHED'
ORDER BY id LIMIT 200000, 20
) page ON page.id = a.id
ORDER BY a.id;优先采用游标分页并为 (status,id) 等真实访问路径建立合适索引。延迟关联只能减少宽行回表,仍要跳过大量索引项。报表导出用分批游标或异步任务,避免用无限扩大 pageSize 的方式拉全量。
验证方法
测试首页、中间页、尾页及并发写入;核对过滤条件不变时游标无重复。比较数据库读取行数与接口内存,记录任意跳页功能的产品取舍。
常见误区
MAX(id) 不等于总行数。游标通常不能直接跳到第 1000 页;排序为时间时只带 ID 也不够,需携带完整稳定排序键。