mysql limit offset 越往后越慢是因为需先扫描跳过前offset行,i/o与cpu开销陡增;推荐用where id > last_id替代,或确保order by字段在联合索引最左且方向一致。

MySQL LIMIT OFFSET 为什么越往后越慢
因为数据库必须先扫描并跳过前 OFFSET 行,才能返回后续结果,数据量大时 I/O 和 CPU 开销陡增。不是“查得慢”,是“跳得累”。
- 场景:用户翻到第 1000 页,
LIMIT 20 OFFSET 20000,MySQL 实际读了 20020 行才取最后 20 条 - 索引没用上?检查
ORDER BY字段是否在联合索引最左,且类型、方向(ASC/DESC)与查询一致 -
WHERE created_at > '2023-01-01'这类过滤条件能大幅减少扫描基数,比纯OFFSET更靠谱 - 如果主键连续且无删改,可用
WHERE id > last_seen_id LIMIT 20替代OFFSET,性能几乎恒定
PostgreSQL 的 cursor 分页怎么写才不翻车
用游标分页(keyset pagination)本质是把“第 N 页”转成“比上一页最后一条记录更大的下一批”,绕开 OFFSET 的累积成本。
- 必须有确定排序:至少一个非空、唯一、有索引的字段,比如
created_at+id组合 - 错误写法:
WHERE created_at >= '2024-05-01' ORDER BY created_at, id LIMIT 20——>=会导致重复或漏数据 - 正确写法:
WHERE (created_at, id) > ('2024-05-01', 12345) ORDER BY created_at, id LIMIT 20,注意括号和比较符 - 客户端需保存上一页最后一条的完整排序值,不能只存时间——同一秒可能有多条记录
SQL Server 的 OFFSET FETCH 性能陷阱
OFFSET ... FETCH NEXT 看似简洁,但执行计划里仍会生成 Top N Sort,尤其排序字段未索引时,内存压力和 tempdb 写入会飙升。
Hishop.5.2.BETA2版主要更新: [修改] 进一步优化了首页打开速度 [修改] 美化了默认模板 [修改] 优化系统架构,程序标签及SQL查询效率,访问系统页面的速度大大提高 [修改] 采用了HTML模板机制,实现了前台模板可视化编辑,降低模板制作与修改的难度. [修改] 全新更换前后台AJAX技术框架,提升了用户操作体验. 店铺管理 [新增] 整合TQ在线客服 [修改] 后台广告位增加
- 仅当 SQL Server 2012+ 且排序字段已建覆盖索引时,
OFFSET才勉强可用 - 避免
SELECT *配合OFFSET:宽表 + 大偏移 = 大量无用列被读取又丢弃 - 等价替代方案:
WHERE id > @last_id ORDER BY id,配合应用层控制每页数量,更可控 - 如果必须用
OFFSET,确保统计信息最新(UPDATE STATISTICS),否则优化器可能选错索引
跨数据库分页的兼容性雷区
没有银弹语法。不同数据库对 NULL、字符排序、复合索引顺序的处理差异,会让同一套分页逻辑在 PostgreSQL 正常、在 MySQL 返回错序。
-
ORDER BY name ASC:MySQL 默认忽略末尾空格,PostgreSQL 不忽略;SQL Server 对中文排序依赖 collation - NULL 值位置:MySQL 默认
NULLS FIRST,PostgreSQL 默认NULLS LAST,不显式声明容易漏数据 - 不要依赖
LIMIT 20 OFFSET ?这种参数化写法直通多库——要么按数据库切分支,要么统一走 keyset 模式 - 测试时务必用真实数据量(千万级)+ 真实索引结构压测,小数据集看不出
OFFSET的衰减曲线
真正难的不是写出能跑的分页 SQL,而是让下拉加载第十万条记录时,数据库不抖、应用不超时、结果不错乱。这要求你清楚知道每一行扫描代价从哪来,而不是只盯着 LIMIT 数字。









