使用索引游标避免大偏移,确保排序字段有索引,利用覆盖索引减少回表,通过延迟关联优化大表分页,提升mysql分页性能。

在 MySQL 中进行分页查询时,随着数据量增大,性能问题会逐渐显现,特别是使用 LIMIT offset, size 这种方式在偏移量很大时效率很低。优化分页性能的核心是减少全表扫描和避免跳过大量记录。
1. 避免大偏移量的 LIMIT 查询
当执行类似下面的语句时:
select * FROM users ORDER BY id LIMIT 100000, 20;
MySQL 需要先读取前 100020 条记录,再丢弃前 100000 条,只返回最后 20 条,这非常低效。
解决方案: 使用基于索引字段的“游标”方式,比如记录上一页最后一条记录的主键值,下一页从该值之后开始查询。
SELECT * FROM users WHERE id > 100000 ORDER BY id LIMIT 20;
这样可以利用主键索引快速定位,避免扫描前面的数据。
2. 确保排序字段有索引
ORDER BY 字段必须建立合适的索引,尤其是用于分页排序的字段(如 id、create_time)。
例如,如果按创建时间分页:
SELECT * FROM orders ORDER BY create_time DESC LIMIT 20;
应在 create_time 上建立索引:
CREATE INDEX idx_create_time ON orders(create_time);
如果有复合排序条件,使用联合索引更有效。
3. 覆盖索引减少回表
如果查询字段都能被索引覆盖,MySQL 可以直接从索引中获取数据,无需回表查询行数据,大幅提升速度。
例如:
SELECT id, status, amount FROM orders WHERE status = 1 ORDER BY id LIMIT 20;
可以建立覆盖索引:
CREATE INDEX idx_status_id_amount ON orders(status, id, amount);
这个索引能完全支持查询条件、排序和字段输出,避免访问数据行。
4. 延迟关联优化大表分页
对于需要查询大量字段的大表,可先通过索引获取主键,再用主键关联原表获取完整数据。
例如:
SELECT u.* FROM users u INNER JOIN ( SELECT id FROM users WHERE dept_id = 10 ORDER BY id LIMIT 100000, 20 ) AS tmp ON u.id = tmp.id;
子查询只走索引获取 id,外层再根据 id 查具体数据,减少排序和临时表开销。
基本上就这些方法。关键点是避免大 offset,善用索引,尽量减少数据扫描和回表次数。合理设计分页逻辑,必要时改用“加载更多”或时间戳分页,性能会更稳定。