news 2026/4/25 15:05:44

12s 到 200ms,MySQL 2000万订单数据 6 种深度分页优化全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
12s 到 200ms,MySQL 2000万订单数据 6 种深度分页优化全解析

那晚,大约晚上 11 点,我与 Chaya 在丽江的洱海酒店享受两人世界的快乐,电商平台的运维大群突然炸开了锅。

监控系统发出刺耳的警报:订单查询接口响应时间从200ms 飙升到 12 秒,数据库 CPU 利用率突破 90%。

发现事故根源竟是一个看似平常的查询——用户中心的历史订单分页查询。

这背后隐藏的正是MySQL 深度分页的典型问题——数据越往后查,速度越让人抓狂。

其本质是传统分页机制在数据洪流下的失效:LIMIT 100000,10这样的查询,会让数据库像逐页翻阅千页文档的抄写员,机械地扫描前 10 万条记录再丢弃。

当数据量突破千万级时,这种暴力扫描不仅造成 I/O 资源的巨大浪费,更会导致关键业务查询的链式阻塞。

本文将深入拆解深度分页的技术黑箱,通过电商订单表等真实场景,揭示 B+树索引与分页机制的碰撞奥秘,并给出 6 种经过实战检验的优化方案。

深度分页

假设电商平台的订单表存储了 2000 万条记录,表结构如下,主键是id,(user_id + create_time)联合索引。

REATE TABLE `orders` ( `id` int NOT NULL AUTO_INCREMENT, -- id自增 `user_id` int DEFAULT NULL, `amount` decimal(10,2) DEFAULT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, -- 创建时间默认为当前时间 PRIMARY KEY (`id`), KEY `idx_userid_create_time` (`user_id`, `create_time`) -- 创建时间设置为普通索引 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

我们的分页语句一般这么写。

SELECT * FROM orders WhERE user_id = 'Chaya' ORDER BY create_time DESC LIMIT 0, 20;

当用户查询第 1000 页的订单(每页 20 条),常见的分页写法如下。

SELECT * FROM orders WhERE user_id = 'Chaya' ORDER BY create_time DESC LIMIT 19980, 20;

执行流程解析:

  1. 使用联合索引idx_userid_create_time读取 19980 + 20 条数据。

  2. 利用索引在内存中排序。

  3. 丢弃 19880 条数据,返回剩下的 20 条。

随着页码增加,需要处理的数据量会线性增长。当 offset 达到 10w 时,查询耗时会显著增加,达到 100w 时,甚至需要数秒。

游标分页(Cursor-based Pagination)

适用场景:支持连续分页(如无限滚动)。

实现原理:基于有序且唯一的字段(如自增主键 ID),通过记录上一页最后一条记录的标识(如主键 ID),将WHERE条件与索引结合,跳过已查询数据。

-- 第一页 SELECT * FROM orders WhERE user_id = 'Chaya' ORDER BY create_time DESC LIMIT 20; -- 后续页(记录上一页查询得到的 id,id=1000) SELECT id, user_id, amount FROM orders WHERE id > 1000 AND user_id = 'Chaya' ORDER BY create_time DESC LIMIT 20;

索引树直接定位到order_id=1000的叶子节点,仅扫描后续 1000 条记录,避免遍历前 100 万行数据。

优势

  • 完全避免OFFSET扫描,时间复杂度从 O(N)降为 O(1)

  • 天然支持顺序分页场景(如无限滚动加载)

限制

  • 不支持随机跳页(如直接跳转到第 1000 页)

  • 需保证排序字段唯一且有序

延迟关联(Deferred Join)

实现原理通过子查询先获取主键范围,再关联主表获取完整数据。减少回表次数,利用覆盖索引优化性能。

SELECT t1.* FROM orders t1 INNER JOIN ( SELECT id FROM orders WhERE user_id = 'Chaya' ORDER BY create_time DESC LIMIT 1000000, 20 ) t2 ON t1.id = t2.id;

优势

  • 子查询仅扫描索引树,避免回表开销。

  • 主查询通过主键精确匹配,效率极高。

  • 性能提升可达 10 倍以上(实测从 1.2 秒降至 0.05 秒)。

覆盖索引优化

实现原理:创建包含查询字段的联合索引,避免回表操作。例如索引设计为(user_id, id, create_time, amount)

ALTER TABLE orders ADD INDEX idx_cover (user_id, id, create_time,amount); SELECT id, user_id, amount, create_time FROM orders USE INDEX (idx_cover) WhERE user_id = 'Chaya' ORDER BY create_time DESC LIMIT 1000000, 20;

Chaya:订单很多字段的,我想查看更多订单细节怎么办?

这个问题问得好,我们可以设计订单列表和详情页,通过上述方案做订单列表的分页查询;点击详情页的时候,在使用订单 id 查询订单。

分区表

实现原理:将大表按时间或哈希值水平拆分。例如按月分区,每个分区独立存储,缩小扫描范围。

-- 按月份RANGE分区 ALTER TABLE orders PARTITION BY RANGE (YEAR(create_time)*100 + MONTH(create_time)) ( PARTITION p202501 VALUES LESS THAN (202502), PARTITION p202502 VALUES LESS THAN (202503) ); -- 查询特定月份数据 SELECT * FROM orders PARTITION (p202501) WHERE user_id = 'chaya' ORDER BY create_time DESC LIMIT 20;

预计算分页(Precomputed Pages)

实现原理:通过异步任务预生成分页数据,存储到 Redis 或物化视图。适合数据更新频率低的场景。

实现步骤

  1. 定时任务生成热点页数据。

  2. 存储到 Redis 有序集合。

ZADD order_pages 0 "page1_data" 1000 "page2_data"
  1. 查询的时候直接获取缓存数据

-- 伪代码:获取第N页缓存 ZRANGEBYSCORE order_pages (N-1)*1000 N*1000

集成 Elasticsearch

实现原理:利用 ES 的search_after特性,通过游标实现深度分页。结合数据同步工具保证一致性。

实现流程:canal+kafka 订阅 MySQL binlog 将数据异构到 elasticsearch。

elasticsearch 保存的数据主要就是我们的查询条件和订单 id。

订单表 → Binlog → Canal → Kafka → Elasticsearch、Hbase

在查询的时候,通过 Elasticsearch 查询得到订单 ID,最后在根据订单 ID 去 MySQL 查询。

或者我们可把数据全量同步到 Hbase 中查询,在 Hbase 中查询完整的数据。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 14:19:22

C#调用REST API访问部署在服务器上的GLM-4.6V-Flash-WEB服务

C#调用REST API访问部署在服务器上的GLM-4.6V-Flash-WEB服务 在企业智能化升级的浪潮中,越来越多业务系统开始集成视觉理解能力——从发票识别、合同解析到智能客服中的图文问答。然而,训练和部署一个真正可用的多模态大模型,往往意味着高昂的…

作者头像 李华
网站建设 2026/4/17 19:03:09

如何利用GLM-4.6V-Flash-WEB提升图文理解效率?开发者必看

如何利用GLM-4.6V-Flash-WEB提升图文理解效率?开发者必看 在智能客服自动识别用户上传截图、内容平台实时审核图片信息、企业自动化处理大量图表文档的今天,传统的“OCR规则”方法早已力不从心。图像中的语义复杂性——比如一张医疗报告是否包含高风险诊…

作者头像 李华
网站建设 2026/4/19 11:23:40

ComfyUI工作流集成GLM-4.6V-Flash-WEB视觉理解节点

ComfyUI集成GLM-4.6V-Flash-WEB:让视觉理解触手可及 在AI应用日益普及的今天,一个现实问题始终困扰着开发者:如何让强大的多模态模型真正“用得上、跑得快、管得了”?尤其是在图像理解这类高算力需求任务中,传统方案往…

作者头像 李华
网站建设 2026/4/23 7:37:51

【网络安全管理入门】应急响应之挖矿木马实战演练教程,建议收藏!

今天给大家分享一下应急响应之挖矿木马实战演练教程。 喜欢的朋友们,记得给我点赞支持和收藏一下,关注我,学习黑客技术。 什么是挖矿木马 挖矿木马是一种恶意软件,它在未经用户许可的情况下,利用用户的计算资源来挖…

作者头像 李华
网站建设 2026/4/25 8:35:29

HuggingFace镜像网站归档GLM-4.6V-Flash-WEB历史版本

HuggingFace镜像网站归档GLM-4.6V-Flash-WEB历史版本 在当今AI应用加速落地的浪潮中,多模态大模型正从实验室走向真实业务场景。无论是电商平台的内容审核、智能客服的图文问答,还是教育产品的图像解析,开发者面临的不再是“有没有模型可用”…

作者头像 李华
网站建设 2026/4/23 17:30:35

然然管理系统-双前端加持!基于Ant Design Vue 4.x的前端正在开发中

在企业级管理系统开发领域,技术栈的选择往往决定了开发效率、系统稳定性和用户体验。今天给大家推荐一款兼顾灵活性与实用性的管理系统 ——然然管理系统,后端基于 SpringBootMyBatisPlus 构建稳定高效的服务层,前端不仅适配了经典的 Vue3Ele…

作者头像 李华