LIMIT offset, row_count最稳妥;LIMIT row_count OFFSET offset在MySQL 5.5+也可用;禁用LIMIT row_count, offset以免语法错误。

MySQL 的 LIMIT 语法到底怎么写才不翻车
直接说结论:LIMIT offset, row_count 是最稳妥的写法,但 LIMIT row_count OFFSET offset 在 MySQL 5.5+ 也完全可用,二者语义一致。别用 LIMIT row_count, offset —— 这是常见笔误,MySQL 会把它当成交互式错误参数顺序,报 SQL syntax error。
为什么 OFFSET 越大分页越慢
MySQL 不支持“跳过前 N 行再取 M 行”的索引跳跃优化。执行 LIMIT 10000, 20 时,它仍要扫描并丢弃前 10000 行(哪怕有索引),再返回后 20 行。尤其在高并发或大表场景下,CPU 和 I/O 压力陡增。
- 真实影响:100 万行表查第 1000 页(
LIMIT 99990, 20)可能耗时超 800ms;而第 1 页通常不到 5ms - 规避思路:用游标分页(
WHERE id > last_seen_id ORDER BY id LIMIT 20)替代 OFFSET,前提是排序字段有索引且唯一/基本唯一 - 注意:如果业务允许“不严格连续页码”,游标方式几乎无性能衰减
ORDER BY 必须和 LIMIT 一起用吗
不是必须,但强烈建议加。没 ORDER BY 时,LIMIT 返回的行顺序由存储引擎决定(比如 InnoDB 的聚簇索引物理顺序),结果不可预测,不同查询、不同 MySQL 版本、甚至同一查询多次执行都可能返回不同记录。
- 典型翻车场景:前端分页列表刷新后顺序乱了,用户以为数据错乱
- 安全做法:只要用了
LIMIT,就显式加上确定性排序,例如ORDER BY created_at DESC, id DESC - 如果排序字段有重复值(如多个同秒的
created_at),务必补一个唯一字段(如id)做二级排序,否则分页可能漏行或重复
分页总数 count(*) 怎么查才不至于拖垮数据库
对大表执行 SELECT COUNT(*) FROM t WHERE ... 是全表(或全索引)扫描,开销和主查询本身接近,尤其是带复杂 WHERE 条件时。这不是“要不要查”的问题,而是“怎么查更合理”。
- 方案一:缓存总数 —— 比如每小时用定时任务更新一次
SELECT COUNT(*)结果到 Redis,误差可接受 - 方案二:估算总数 —— 查
SHOW TABLE STATUS LIKE 't'中的Rows字段(MyISAM 精确,InnoDB 是估算值,误差常在 ±10%) - 方案三:前端不显示总页数 —— 改为“下一页”按钮 + 到底后禁用,避免用户盲目跳转到末页
真正容易被忽略的是:即使你只查一页数据,如果同时查了精确总数,那两个查询加起来的代价可能比单次查 100 页还高。










