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 做了什么——以及有没有索引支撑那个“前面”。
