
当数据量大时,直接用 LIMIT offset, size 做分页会越来越慢,尤其 offset 很大(比如 100 万)时,MySQL 仍需扫描前 100 万行才能跳到目标位置。真正高效的分页不是靠“跳过”,而是“定位”。
用主键/唯一索引做游标分页(推荐)
适用于按主键(如 id)或时间字段(如 created_at)有序查询的场景。核心思想是:不依赖 offset,而是记录上一页最后一条的主键值,下一页从该值之后开始查。
Hishop.5.2.BETA2版主要更新: [修改] 进一步优化了首页打开速度 [修改] 美化了默认模板 [修改] 优化系统架构,程序标签及SQL查询效率,访问系统页面的速度大大提高 [修改] 采用了HTML模板机制,实现了前台模板可视化编辑,降低模板制作与修改的难度. [修改] 全新更换前后台AJAX技术框架,提升了用户操作体验. 店铺管理 [新增] 整合TQ在线客服 [修改] 后台广告位增加
- 第一页:SELECT * FROM orders WHERE status = 1 ORDER BY id ASC LIMIT 20
- 第二页(假设第一页最后 id 是 1056):SELECT * FROM orders WHERE status = 1 AND id > 1056 ORDER BY id ASC LIMIT 20
- 优势:每次都是范围查询 + 索引覆盖,无需扫描跳过行,响应稳定在毫秒级
- 注意:ORDER BY 字段必须有索引;不能跳页(如直接翻到第 100 页),但符合多数列表滚动场景
延迟关联优化大 offset 场景
当必须支持任意页码跳转(如后台管理),且主键无法用于游标时,可用“先查 ID,再关联详情”的方式减少回表开销。
- 原始低效写法:SELECT * FROM users ORDER BY id LIMIT 100000, 20
- 优化写法:SELECT u.* FROM users u INNER JOIN (SELECT id FROM users ORDER BY id LIMIT 100000, 20) t ON u.id = t.id
- 原理:子查询只扫描主键索引(轻量),外层再通过主键精准回表,避免全字段扫描前 10 万行
- 适用:MySQL 5.7+,且表有主键/唯一索引;效果取决于索引宽度和数据分布
避免常见陷阱
- 不要在无索引字段上 ORDER BY + LIMIT:会导致 filesort,offset 越大越慢
- 慎用 COUNT(*) 分页总数:大表全表统计极耗资源;可改用估算(如 SHOW TABLE STATUS)、缓存总数、或前端“加载更多”代替总页数展示
- 注意 NULL 和边界值:若排序字段含 NULL,需明确指定 NULLS FIRST/LAST(MySQL 8.0+ 支持),或在 WHERE 中过滤
- 复合排序需一致索引:如 ORDER BY category, id,则索引应为 (category, id),否则无法高效利用
其他实用技巧
- 对高频分页字段(如 status + created_at)建立联合索引,让排序和过滤同时走索引
- 用 EXPLAIN 检查执行计划,确认 key、rows、Extra(尤其避免 Using filesort / Using temporary)
- 业务允许时,限制最大页码(如只允许查前 1000 页),或改用搜索+筛选替代深度分页









