SQLPathLab
SQL 实战指南 · MySQL 8.0

OFFSET 分页为什么越来越慢

比较 OFFSET 与游标分页的扫描成本、稳定排序和数据变化下的翻页结果。

问题与判断方法

LIMIT 加 OFFSET 适合数据量较小、需要直接跳到指定页码的后台列表。它的优势是实现简单、页码直观;但页码越深,数据库通常需要定位并丢弃越多前置记录,响应时间会随偏移量增长。

游标分页也叫 keyset pagination。它不记录“第几页”,而是记录上一页最后一行的排序键,再用 WHERE 从该位置之后继续读取。以主键升序为例,条件是 id > last_id,索引可以直接定位新的起点。

排序字段不唯一时,游标必须携带完整排序键。例如 ORDER BY created_at DESC, id DESC 对应的下一页条件要同时比较 created_at 与 id;只记录时间会在同一秒有多行时造成重复或遗漏。

数据变化也会影响选择。OFFSET 按位置翻页,前面插入或删除一行会推动后续位置;游标围绕已见过的最后一个键继续,通常更适合信息流和连续浏览,但它不方便随机跳到第 500 页。

上线前应针对真实索引和目标页深度比较 EXPLAIN ANALYZE,并明确接口是否需要总页数、任意跳页、正反向翻页以及排序字段是否可变。不要只根据四行演示数据推断生产性能。

示例

示例数据表

表名:orders
orders
idcustomer_idproduct_idnamedepartmentamountstatuscreated_atdiscount
1 101 201 Alice Sales 1200 paid 2026-01-03 0
2 102 202 Bob IT 900 pending 2026-01-08 50
3 101 201 Cindy Sales 1500 paid 2026-02-02 100
4 104 203 David HR 700 cancelled 2026-02-15 0

优化前 / 不推荐

SELECT * FROM orders ORDER BY id LIMIT 2 OFFSET 2;

优化前运行结果

result
idcustomer_idproduct_idnamedepartmentamountstatuscreated_atdiscount
3 101 201 Cindy Sales 1500 paid 2026-02-02 100
4 104 203 David HR 700 cancelled 2026-02-15 0

优化后 / 推荐

SELECT * FROM orders WHERE id > 2 ORDER BY id LIMIT 2;

优化后运行结果

result
idcustomer_idproduct_idnamedepartmentamountstatuscreated_atdiscount
3 101 201 Cindy Sales 1500 paid 2026-02-02 100
4 104 203 David HR 700 cancelled 2026-02-15 0

为什么这样更好:样例结果相同,但机制不同:OFFSET 先越过两行,游标条件以主键 2 为已知位置开始读取;偏移量增大时差异才会放大。

这篇内容是否清楚?