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本身,而是它掩盖了没建对索引、没设计好分页逻辑、或者把数据库当缓存用的问题。
