limit 在 where、order by 之后执行,即 where→group by→having→select→order by→limit;深分页(如 limit 10000,10)性能差,推荐游标分页;窗口函数分页通常更慢,不建议仅用于分页。
MySQL 中 LIMIT 是在 WHERE、ORDER BY 之后执行的
很多人误以为 LIMIT 会“提前截断”数据来提升性能,其实它是在整个查询逻辑处理完后才生效的。具体顺序是:WHERE 过滤 → GROUP BY 分组 → HAVING 筛选 → SELECT 投影 → ORDER BY 排序 → 最后才是 LIMIT 取行。这意味着即使你只想要前 10 行,MySQL 仍可能扫描并排序全部匹配结果(尤其没走索引时)。
常见错误现象:SELECT * FROM orders WHERE status = 'paid' ORDER BY created_at DESC LIMIT 10 在 status 无索引、created_at 也未被联合覆盖时,会全表扫描 + 文件排序,再丢弃 99.9% 的行。
- 确认是否命中索引:用
EXPLAIN查看key和Extra字段,重点看有没有Using filesort或Using temporary - 如果
ORDER BY字段和WHERE条件字段不同,考虑创建联合索引,例如(status, created_at) -
LIMIT后带偏移量(如LIMIT 10000, 10)会导致 MySQL 跳过前 10000 行——这些行仍要被读取、排序、丢弃,性能陡降
分页场景下 LIMIT offset, size 的性能陷阱
传统 LIMIT 10000, 20 分页在大数据集上非常危险:MySQL 必须定位到第 10001 行,意味着它得按排序顺序“数”够 10000 行,哪怕只返回 20 行。offset 越大,越接近全量扫描成本。
典型表现:第 1 页很快,第 500 页响应时间飙升,慢查询日志里反复出现同一类语句。
- 避免深分页:用游标分页(cursor-based pagination),基于上一页最后一条记录的排序字段值继续查,例如
WHERE created_at - 如果必须用 offset,确保
ORDER BY字段有高选择性索引,且尽量让WHERE条件大幅缩小结果集 - 注意:主键自增不等于排序稳定,若业务允许按
id分页,WHERE id > ? ORDER BY id LIMIT 20比LIMIT 10000, 20快一个数量级
MySQL 8.0+ 的窗口函数能否替代 LIMIT 分页?
不能直接替代。像 ROW_NUMBER() OVER (ORDER BY ...) 生成序号后过滤,本质仍是先算出全部序号(即全量排序),再 WHERE rn BETWEEN 10001 AND 10020,性能通常比原生 LIMIT 更差——因为多了临时表和额外计算开销。