分页查询在大数据量场景下,索引扫描往往是性能瓶颈。下面从原理 → 常见问题 → 优化策略 → 示例几个层面系统说明。
常见分页 SQL:
SELECT * FROM orders
ORDER BY create_time
LIMIT 20 OFFSET 100000;
OFFSET 100000 表示先扫描并跳过前 10 万行✅ 索引能避免全表扫描,但无法避免 OFFSET 带来的成本
避免 OFFSET,用“游标 / 位置”代替“跳过”
SELECT *
FROM orders
ORDER BY id
LIMIT 20 OFFSET 100000;
SELECT *
FROM orders
WHERE id > 100000
ORDER BY id
LIMIT 20;
✅ 利用 主键 / 唯一索引 ✅ 时间复杂度接近 O(limit)
SELECT *
FROM orders
WHERE user_id = 123
ORDER BY create_time DESC
LIMIT 20 OFFSET 1000;
SELECT *
FROM orders
WHERE user_id = 123
AND create_time < '2024-01-01 10:00:00'
ORDER BY create_time DESC
LIMIT 20;
✅ 前提:
(user_id, create_time)
✅ 用上一页最后一条的 create_time 作为游标
如果只需要部分字段:
SELECT id, create_time
FROM orders
WHERE user_id = 123
ORDER BY create_time DESC
LIMIT 20;
索引:
(user_id, create_time, id)
✅ 索引覆盖查询
✅ 避免回表,性能提升明显
SELECT *
FROM orders
ORDER BY create_time
LIMIT 20 OFFSET 100000;
SELECT o.*
FROM orders o
JOIN (
SELECT id
FROM orders
ORDER BY create_time
LIMIT 20 OFFSET 100000
) t ON o.id = t.id;
✅ 子查询只扫描索引
✅ 主表只回表 20 条
⚠ 但 OFFSET 仍然存在,不如游标分页
❌ 慢:
ORDER BY create_time
-- 无索引
✅ 快:
ORDER BY create_time
-- 有索引
⚠ 排序字段必须在索引中
| 查询 | 推荐索引 |
|---|---|
| ORDER BY id | PRIMARY KEY |
| WHERE a ORDER BY b | (a, b) |
| WHERE a ORDER BY b LIMIT | (a, b, id) |
| 时间翻页 | (user_id, create_time) |
ORDER BY create_time
INDEX (user_id)
❌ 索引无法用于排序
LIMIT + OFFSET 无法走索引跳过WHERE id > ?FETCH NEXT 20 ROWS ONLYROWNUM 或 FETCH FIRSTROWID 或业务主键游标❌ 需要:
✅ 只能:
分页查询优化的本质:用索引定位,而不是用 OFFSET 跳过
如果你愿意,可以:
我可以帮你设计最优分页索引方案。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。