mysql的limit必须置于最外层select末尾,仅支持单数字或双数字(偏移量+行数)语法,且需配合order by保证结果确定性;分页应避免大offset,改用游标分页;update/delete中limit仅为安全限制,不可替代where;sql_calc_found_rows已弃用。

MySQL 的 LIMIT 必须写在语句末尾,且不能单独用
MySQL 不支持像 PostgreSQL 那样把 LIMIT 放在子查询或 CTE 里随意位置。它只认最外层 SELECT 末尾的 LIMIT,否则直接报错 ERROR 1064。
常见错误现象:在 ORDER BY 前加 LIMIT、嵌套子查询里写 LIMIT、或试图用 LIMIT 限制 UPDATE/DELETE 但没加 WHERE(虽语法允许,但极危险)。
-
LIMIT后可跟一个数字(如LIMIT 10),表示取前 10 行 - 也可跟两个数字(如
LIMIT 20, 10),表示跳过前 20 行,取接下来的 10 行 —— 注意这不是“从第 20 行开始”,而是偏移量为 20 - 如果只想要最新一条记录,别只写
LIMIT 1,必须配合ORDER BY created_at DESC,否则结果不确定
分页时 LIMIT offset, size 越往后越慢,替代方案要提前想
当 offset 很大(比如 LIMIT 100000, 20),MySQL 仍会扫描前 100020 行再丢弃,IO 和 CPU 开销陡增。这不是语法问题,是执行逻辑决定的。
使用场景:后台列表翻到几百页后卡顿、导出任务中途超时。
- 用游标分页(cursor-based pagination):改用上一页最后一条的
id或时间戳做条件,例如WHERE id > 12345 ORDER BY id LIMIT 20 - 避免
OFFSET超过 10 万级;真要全量导出,优先用mysqldump或按主键范围分段查 - 注意
ORDER BY字段必须有索引,否则LIMIT加速效果归零
LIMIT 在 UPDATE 和 DELETE 中能用,但风险极高
MySQL 允许在 UPDATE 和 DELETE 后加 LIMIT,比如 DELETE FROM logs WHERE status = 'error' LIMIT 1000。这能防止误删全表,但容易掩盖逻辑缺陷。
常见错误现象:脚本循环执行带 LIMIT 的 DELETE,却没检查是否还有剩余数据,导致删不干净;或者没加 WHERE 条件,仅靠 LIMIT 挡着,一运行就删错行。
- 生产环境禁止无
WHERE的DELETE ... LIMIT,哪怕只是测试 - 批量清理务必先用
SELECT COUNT(*)预估影响行数,再用LIMIT分批操作 -
UPDATE ... LIMIT同样依赖WHERE精准定位,LIMIT只是保险绳,不是筛选逻辑
和 SQL_CALC_FOUND_ROWS 配合查总条数,现在基本该淘汰了
老项目里常见这种写法:SELECT SQL_CALC_FOUND_ROWS * FROM users LIMIT 20,再执行 SELECT FOUND_ROWS()。它会让 MySQL 强制扫描全表统计,即使你只取前 20 行。
性能影响明显:在千万级表上,SQL_CALC_FOUND_ROWS 可能比单纯 LIMIT 慢 5–10 倍。
- 现代做法是:前端分页显示“下一页”,不显示总页数;或用近似值(如
EXPLAIN的rows字段)预估 - 真需要精确总数,另起一个轻量
SELECT COUNT(*),但记得加好WHERE条件,且避免在高并发写入场景频繁查 -
SQL_CALC_FOUND_ROWS在 MySQL 8.0.17+ 已被标记为 deprecated,后续版本会移除
真正麻烦的从来不是 LIMIT 本身,而是它掩盖了没建对索引、没设计好分页逻辑、或者把数据库当缓存用的问题。










