344 字
2 分钟
MySQL 深分页为什么慢,如何改写
LIMIT 100000, 20 通常需要定位并跳过前 100000 条候选记录,再返回 20 条;即使排序由索引提供,跳过工作仍存在。若使用二级索引排序又回表,深分页还可能对大量被丢弃记录做不必要的回表。
一种改写是先在覆盖索引中找出本页主键,再回表取少量完整行:
SELECT o.*FROM orders AS oJOIN ( SELECT id FROM orders WHERE user_id = 42 ORDER BY created_at DESC, id DESC LIMIT 100000, 20) AS page USING (id)ORDER BY o.created_at DESC, o.id DESC;索引可考虑 (user_id, created_at, id),但降序定义和执行计划需结合版本核验。若产品允许游标翻页,可用上一页最后一条的 (created_at,id) 作为锚点:WHERE user_id=42 AND (created_at,id)<(?,?) ORDER BY created_at DESC,id DESC LIMIT 20。排序必须有唯一的稳定 tie-breaker;游标模式不便直接跳到任意页,数据变化也会影响不同分页语义。
追问
- 加索引能彻底解决大 OFFSET 吗? 不能消除跳过大量记录的成本,但匹配索引可避免排序或减少回表。
- 游标翻页的限制是什么? 适合连续向前/向后翻页,不适合任意页码跳转;要设计稳定排序键。
- 为什么排序要加主键? 排序字段可能重复,主键作为唯一 tie-breaker 保证分页边界确定。
MySQL 深分页为什么慢,如何改写
https://blog.xqcherry.top/posts/interview/mysql/deep-pagination/ 目录