必须配合 ORDER BY 使用 LIMIT,否则结果无序且不可靠;优先用游标分页替代 OFFSET;注意不同数据库分页语法差异;子查询和 CTE 中 LIMIT 需谨慎使用。

MySQL 里用 LIMIT 直接截断结果,但别漏写ORDER BY
不加 ORDER BY 的LIMIT是危险的:数据库可能每次返回不同行,尤其表有并发写入时。MySQL 不保证无序查询的行顺序,LIMIT 10可能今天取前 10 条,明天就变成另 10 条。
- 必须配合确定性排序,比如
ORDER BY id ASC或ORDER BY created_at DESC -
LIMIT放在语句末尾,语法简单:SELECT * FROM users ORDER BY id LIMIT 20 - 如果只想要第 1 条,写
LIMIT 1比LIMIT 0,1更清晰,也少一个参数要维护
分页查第 N 页数据,OFFSET越往后越慢
OFFSET本质是跳过前 N 行再取数据,数据库仍需扫描并丢弃那些行。查第 1000 页(每页 20 条)相当于跳过 20000 行——索引可能失效,I/ O 和 CPU 开销陡增。
- 替代方案优先考虑「游标分页」:用上一页最后一条记录的
id做条件,如WHERE id > 12345 ORDER BY id LIMIT 20 - 真要用
OFFSET,确保ORDER BY字段有索引,且避免OFFSET超过几万 - PostgreSQL 和 SQLite 支持
LIMIT/OFFSET,但 SQL Server 得用OFFSET …… FETCH NEXT,语法不同
不同数据库的分页语法差异不止是关键字
不是所有数据库都认LIMIT,硬套会报错。比如 SQL Server 报Incorrect syntax near 'LIMIT',Oracle 旧版本压根没LIMIT。
- MySQL / PostgreSQL / SQLite:
LIMIT 20 OFFSET 40或LIMIT 40, 20(MySQL 特有逗号写法) - SQL Server 2012+:
ORDER BY id OFFSET 40 ROWS FETCH NEXT 20 ROWS ONLY - Oracle 12c+:
OFFSET 40 ROWS FETCH NEXT 20 ROWS ONLY;老版本得用ROWNUM嵌套子查询,容易出错 - 如果用 ORM(如 Django ORM、SQLAlchemy),让框架生成适配方言的分页语句,别手写原生 SQL
LIMIT在子查询或 CTE 里被忽略?注意执行顺序
有些场景下 LIMIT 看似写了却没生效,常见于子查询未加 ORDER BY,或者 CTE 里用了LIMIT 但外层查询又没约束。
- 子查询中
LIMIT必须搭配ORDER BY才有意义,否则优化器可能直接忽略 - CTE(
WITH语句)里的LIMIT只作用于该 CTE,不会影响主查询结果集大小 - 聚合后分页要小心:先
GROUP BY再LIMIT,别在聚合前LIMIT——那样会漏掉本该合并的分组 - 测试时用
EXPLAIN看执行计划,确认LIMIT是否真正下推到扫描层
分页这事,表面是加个 LIMIT,实际牵扯排序稳定性、索引利用、方言兼容和执行计划。最容易被忽略的是:没有ORDER BY 的LIMIT根本不算分页,只是随机抽样。