limit 在排序和去重之后执行,非提前截断;无 order by 时可能早停但不保证,有 order by 时必全量排序后取前 n 行;深分页性能差因需跳过 offset 行,推荐游标分页。

MySQL 中 LIMIT 是在排序和去重之后才生效的
很多人误以为 LIMIT 会“提前截断”数据来提升性能,实际并非如此。MySQL 的执行顺序决定了它必须先完成 WHERE 过滤、JOIN、GROUP BY、HAVING、ORDER BY 和 DISTINCT(如果存在),最后才应用 LIMIT。这意味着:即使你只想要前 10 行,MySQL 仍可能扫描并排序全部匹配结果(除非有覆盖索引或优化器能下推)。
LIMIT 对执行计划的影响取决于是否有 ORDER BY
没有 ORDER BY 时,MySQL 可能尽早停止扫描(尤其使用索引且满足条件后),但不保证;有 ORDER BY 时,必须拿到所有符合条件的行并完成排序后才能取前 N 行——这是最常被低估的性能陷阱。
- 带
ORDER BY id+LIMIT 10:若id有索引,通常能用索引有序扫描,只需读 10 行 - 带
ORDER BY created_at+LIMIT 10:若created_at无索引,需 filesort + 全表扫描再取前 10 - 带
ORDER BY RAND()+LIMIT 1:必须为每行计算随机值并排序,代价极高
子查询中写 LIMIT 可能报错,必须显式命名
在 MySQL 5.7+ 中,包含 LIMIT 的子查询若未加别名,会触发错误:This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' 或更常见的 You have an error in your SQL syntax。这是因为语法解析器要求派生表(derived table)必须有别名。
SELECT * FROM ( SELECT id, name FROM users ORDER BY id DESC LIMIT 5 ) AS recent_users;
- 漏掉
AS recent_users→ 报错 -
LIMIT不能用于视图定义中(除非是 MySQL 8.0.22+ 的可更新视图限制放宽) - 存储过程里动态拼接 SQL 时,
LIMIT ?参数需用PREPARE+EXECUTE,不能直接写LIMIT @n
分页深翻(LIMIT 1000000, 20)为什么慢?
MySQL 不支持跳过前 N 行的“游标式”跳转,LIMIT offset, size 本质是让服务器先读出 offset+size 行,再丢弃前 offset 行。offset 越大,I/O 和内存开销越不可控。
-
LIMIT 1000000, 20可能触发临时表 + filesort,甚至 OOM - 替代方案不是“优化 LIMIT”,而是改用基于游标的分页(如
WHERE id > 123456 ORDER BY id LIMIT 20) - 如果业务允许,用
SQL_CALC_FOUND_ROWS已被弃用(MySQL 8.0.17+ 移除),应改用单独SELECT COUNT(*)
真正影响性能的从来不是 LIMIT 这个词本身,而是它前面那部分 SQL 做了什么——以及有没有索引支撑那个“前面”。









