在关系型数据库中,分页查询(LIMIT/OFFSET)如果不用索引,往往会变成“先全表扫描、再丢弃前面记录”,随着 OFFSET 变大,性能急剧下降。
“用索引扫描做分页”的核心思想是:让数据库通过索引直接定位起始位置,而不是扫描并跳过大量行。
下面按常见场景说明。
SELECT id, name
FROM user
ORDER BY id
LIMIT 10 OFFSET 1000;
id 是主键,MySQL 等数据库仍可能:
确保:
ORDER BY 的列有索引-- id 是主键索引
SELECT id
FROM user
ORDER BY id
LIMIT 10 OFFSET 1000;
也叫 Keyset Pagination / Seek Method
不跳过记录,而是从某个索引值之后开始扫
-- 上一页最后一条记录的 id
SELECT id, name
FROM user
WHERE id > 1000
ORDER BY id
LIMIT 10;
✅ 优点:
PRIMARY / INDEX RANGE SCAN✅ 执行计划通常是:
Index Range Scan
ORDER BY create_time DESC, id DESC
CREATE INDEX idx_user_ct_id
ON user(create_time, id);
SELECT id, create_time
FROM user
WHERE (create_time, id) < ('2024-01-01 10:00:00', 5000)
ORDER BY create_time DESC, id DESC
LIMIT 10;
不同数据库语法略有差异(MySQL 8 / PostgreSQL 支持元组比较)
❌ 以下会导致索引无法用于分页:
ORDER BY 字段无索引ORDER BY 多字段顺序不一致ORDER BY DATE(create_time)
OFFSET 极大但无游标| 方式 | 是否用索引扫描 | OFFSET 变大 | 推荐度 |
|---|---|---|---|
| LIMIT OFFSET | 可能全表 | 越来越慢 | ❌ |
| 索引 ORDER BY | 部分 | 仍慢 | ⚠️ |
| 游标分页 | ✅ 索引范围扫描 | 稳定 | ✅✅✅ |
分页要用索引扫描,就不要用 OFFSET,而要用“上次最大索引值”做范围查询。
如果你用的是 MySQL / PostgreSQL / Oracle,或者有特殊业务(复合排序、联表分页),可以告诉我,我可以给你针对性 SQL。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。