MySQL实战:基于游标与覆盖索引的高效分页解决分页查询卡顿

B站影视 内地电影 2025-06-05 16:42 2

摘要:根本原因:传统的LIMIT offset, size分页方式在大数据量下会产生全表扫描+临时排序,当offset值达到10万量级时,MySQL需要遍历并丢弃前10万行数据才能返回结果。今天给大家分享游标分页与覆盖索引两大核心技术,实测将百万级数据分页耗时从秒级

你是否遇到过这样的场景?

用户浏览电商订单时,翻到第100页需要等待8秒后台管理系统查询日志,每次翻页都触发数据库CPU飙升移动端APP瀑布流加载,越往下滑动卡顿越明显

根本原因:传统的LIMIT offset, size分页方式在大数据量下会产生全表扫描+临时排序,当offset值达到10万量级时,MySQL需要遍历并丢弃前10万行数据才能返回结果。今天给大家分享游标分页覆盖索引两大核心技术,实测将百万级数据分页耗时从秒级降至毫秒级!

典型的慢查询示例:

SELECT * FROM order_history WHERE user_id = 100 ORDER BY create_time DESC LIMIT 100000, 10;

执行计划分析

type=ALL(全表扫描)rows=100010(实际扫描行数)Extra=Using filesort(文件排序)

三级性能瓶颈

IO成本:扫描全部索引树或数据页CPU成本:排序丢弃前N条数据网络成本:传输冗余数据

利用有序唯一值作为定位锚点,避免遍历历史数据:

-- 下一页 SELECT * FROM order_history WHERE user_id = 100 AND id > 上一页最后一条ID ORDER BY id ASC LIMIT 10; -- 上一页 SELECT * FROM order_history WHERE user_id = 100 AND id

原始表结构

CREATE TABLE orders ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, amount DECIMAL(10,2), create_time DATETIME, INDEX idx_user_create(user_id, create_time));

优化后查询

-- 第一页 SELECT * FROM orders WHERE user_id = 100 ORDER BY create_time DESC, id DESC LIMIT 10;-- 下一页(假设上一页最后一条create_time='2023-08-20 15:30:00', id=9527) SELECT * FROM orders WHERE user_id = 100 AND (create_time

优化效果

执行时间从**1200ms**降至**8ms**扫描行数从**100010行**变为**10行**

通过索引覆盖避免回表查询,结合延迟关联(Deferred Join) 技术:

SELECT t.* FROM ( SELECT id FROM orders WHERE user_id = 100 ORDER BY create_time DESC LIMIT 100000, 10 ) AS tmp INNER JOIN orders t ON tmp.id = t.id;

表结构

CREATE TABLE user_behavior ( id BIGINT AUTO_INCREMENT, user_id INT, action VARCHAR(20), device VARCHAR(50), log_time DATETIME, PRIMARY KEY(id), INDEX idx_user_log(user_id, log_time));

优化前后对比

-- 原始查询(耗时1.2秒)SELECT * FROM user_behavior WHERE user_id = 500 ORDER BY log_time DESC LIMIT 80000, 20; -- 覆盖索引优化(耗时45毫秒)SELECT t.* FROM ( SELECT id FROM user_behavior WHERE user_id = 500 ORDER BY log_time DESC LIMIT 80000, 20 ) AS tmp INNER JOIN user_behavior t ON tmp.id = t.id;

执行计划变化

子查询Using index(仅扫描索引)主查询Using where(快速主键检索)SELECT t.* FROM ( SELECT id FROM orders WHERE user_id = 100 AND id > 上一页最后ID ORDER BY id ASC LIMIT 10 ) AS tmp INNER JOIN orders t ON tmp.id = t.id;

按时间范围分区后查询:

-- 按月分区 PARTITION BY RANGE (TO_DAYS(create_time)) ( PARTITION p202301 VALUES LESS THAN (TO_DAYS('2023-02-01')), PARTITION p202302 VALUES LESS THAN (TO_DAYS('2023-03-01')), ...); -- 查询指定分区 SELECT * FROM orders PARTITION (p202307) WHERE user_id = 100 ORDER BY create_time DESC LIMIT 10; -- 主库写入INSERT INTO orders(...) VALUES(...); -- 从库分页查询 SELECT * FROM orders_slave WHERE user_id = 100 ORDER BY create_time DESC LIMIT 100000, 10; 优化维度技术手段适用场景查询模式游标分页连续分页(如APP瀑布流)索引设计覆盖索引 + 延迟关联复杂排序分页架构设计分区表 + 读写分离超大数据量场景

互动问答

你在项目中遇到过哪些分页性能问题?最终是如何解决的?欢迎在评论区分享你的实战经验!

来源:免费高清壁纸大全

相关推荐