最安全写法是limit 10 offset 20,offset必须在limit后;错误顺序或旧式写法会报error 1064;大offset性能差因需扫描丢弃前n行;务必配合order by确定排序,推荐游标分页优化。

MySQL LIMIT 和 OFFSET 怎么写才不出错
直接写 LIMIT 10 OFFSET 20 是最安全的写法,顺序不能反——OFFSET 必须在 LIMIT 后面,否则报错 ERROR 1064。MySQL 不支持 LIMIT OFFSET 20, 10 这种旧式写法(那是 PostgreSQL 的风格),也不接受 LIMIT 20, 10 里把偏移量放前面(虽然语法上允许,但语义易混淆,强烈不建议)。
常见错误现象:查第 2 页(每页 10 条)却漏掉第 11 条,或返回空结果——往往是因为 OFFSET 算错了,比如用页码 × 每页条数但没减 1(应是 (page - 1) * size)。
-
LIMIT 10 OFFSET 0:第 1 页 -
LIMIT 10 OFFSET 10:第 2 页(跳过前 10 条) - 别写
LIMIT OFFSET 10 10,会语法报错
大偏移量(OFFSET 很大)时为什么慢
因为 MySQL 仍要扫描并丢弃前 OFFSET 行,哪怕你只要最后 10 条。例如 LIMIT 10 OFFSET 1000000,它得先定位到第 1000001 行,中间所有行都参与索引遍历或全表扫描。
使用场景:后台管理列表页翻到 500 页之后,响应明显变卡;监控发现 EXPLAIN 显示 rows 值巨大,且 Extra 里有 Using filesort 或 Using temporary。
- 优化方向:改用「游标分页」(基于上一页最后一条的主键值,如
WHERE id > 12345 LIMIT 10) - 避免
ORDER BY RAND()+LIMIT,这会导致全表随机排序再截断,极慢 - 复合索引要覆盖
ORDER BY字段 +WHERE条件,否则OFFSET效率雪上加霜
和 ORDER BY 一起用时必须注意什么
没 ORDER BY 的 LIMIT 结果不可靠——MySQL 不保证返回哪几行,尤其表有并发写入时,两次查询同个 LIMIT 可能拿到不同数据。
性能影响:如果 ORDER BY 字段没索引,MySQL 会先排序整个结果集再取前 N 条,内存/磁盘开销陡增;若用了索引但不是最左前缀匹配,也可能退化为文件排序。
- 必须写
ORDER BY id(或带确定性顺序的字段),不要省略 - 复合查询中,
ORDER BY要放在LIMIT前,且不能出现在子查询的SELECT列表里(除非外层再包一层) - 慎用
ORDER BY created_at DESC LIMIT 10配合OFFSET:时间可能重复,导致分页错位(同秒内多条记录)
替代方案:什么时候该放弃 LIMIT/OFFSET
当用户明确只看最新几条(如 feed 流)、或数据按主键严格递增时,游标分页更稳更快。它把「第 N 页」变成「从某 ID 之后取 10 条」,绕过扫描成本。
容易被忽略的地方:游标分页无法直接跳转任意页(比如输入页码 137),也不适合按模糊条件筛选后的分页(如搜索关键词),此时仍得用 OFFSET,但应限制最大可翻页数(如只允许前 200 页)。
- 推荐游标写法:
SELECT * FROM posts WHERE id > 12345 ORDER BY id ASC LIMIT 10 - 禁止在生产环境对
OFFSET做用户可控输入(如 URL 参数直接拼进 SQL),必须校验范围、设上限 - 注意时区和主键类型:若用
DATETIME做游标,要考虑夏令时;若用 UUID,排序无意义,别这么干











