<p> 分页查询性能差主因是大 OFFSET 导致大量数据扫描,解决方法 是使用索引优化。首先确保 ORDER BY 字段有索引以避免 filesort;其次利用覆盖索引使查询仅访问索引即可获取所需字段,减少回表开销。更高效的方案是采用游标分页(键集分页),通过上一页的最后一条记录定位下一页,避免 OFFSET 带来的性能问题,如 select * FROM users WHERE id > 156 ORDER BY id LIMIT 20。此外,结合查询条件时应创建匹配的复合索引,例如 WHERE user_id = 123 AND date >= ‘2024-01-01’ ORDER BY date,应建立(user_id, date) 联合索引,以便同时满足过滤和排序需求。综上,优化核心在于减少扫描行数、合理设计索引结构,并优先使用游标分页替代传统 OFFSET 方式。</p>

在 mysql 中,分页查询是常见的需求,尤其是在处理大量数据时。但随着偏移量(OFFSET)增大,查询性能会显著下降。通过合理使用索引和优化查询方式,可以大幅提升分页效率。
理解 LIMIT 和 OFFSET 的性能问题
典型的分页语句如下:
SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 100000;
这条语句需要跳过前 10 万条记录。MySQL 仍需扫描这些数据,即使不返回,导致 I / O 和 CPU 开销大。如果表没有合适的索引,性能更差。
关键点:
- ORDER BY 字段应有索引,避免文件排序(filesort)
- OFFSET 越大,跳过的行越多,查询越慢
- 全表扫描或临时表可能导致性能急剧下降
使用覆盖索引减少回表
如果查询字段都能被索引包含,MySQL 无需回表查询主表数据,这种索引叫“覆盖索引”。
例如:
CREATE INDEX idx_status_created ON orders (status, created_at);
执行分页时:
SELECT status, created_at FROM orders WHERE status = ‘paid’ ORDER BY created_at LIMIT 20;
这个查询可以直接从索引获取所有数据,极大提升速度。
用游标分页替代 OFFSET
对于 大数据 集,推荐使用基于游标的分页(也叫键集分页),避免 OFFSET。
假设按 id 升序分页,第一页取:
SELECT * FROM users WHERE id > 0 ORDER BY id LIMIT 20;
拿到最后一条记录的 id(比如 156),下一页改为:
SELECT * FROM users WHERE id > 156 ORDER BY id LIMIT 20;
这种方式利用索引快速定位,跳过无效扫描,性能稳定。
适用场景:
- 数据有序且唯一字段可用作游标(如自增 ID、时间戳)
- 用户不关心绝对页码,只前后翻页
- 实时性要求高,不能接受延迟
组合索引与查询条件匹配
当分页结合查询条件时,索引设计要与 WHERE 和 ORDER BY 顺序匹配。
例如:
SELECT * FROM logs WHERE user_id = 123 AND date >= ‘2024-01-01’ ORDER BY date LIMIT 10;
应创建复合索引:
CREATE INDEX idx_user_date ON logs (user_id, date);
这样 MySQL 能直接用索引过滤并排序,避免额外排序操作。
基本上就这些。关键是避免大 OFFSET,善用索引结构,优先考虑游标分页和覆盖索引。对复杂场景,可结合延迟关联进一步优化。不复杂但容易忽略。


