当前位置: 首页 > backend >正文

MySQL 深分页:性能优化

在日常开发中,分页查询是非常常见的需求,通常我们会使用 LIMIT offset, size的方式来实现。例如:

SELECT * FROM table_name ORDER BY id LIMIT 1000000, 10;

这条语句的意图是从表 table_name中查询第 1000001 到 1000010 条记录。然而,当 offset数值很大时,比如百万级别,这个查询会变得异常缓慢。这便涉及到了数据库开发中的一个经典问题 —— ​深分页 问题

本文将从原理出发,深入分析 MySQL 深分页为何性能低下,介绍几种常见且实用的优化方案,并在文章最后整理一些 Java 秋招高频面试题,供读者参考。


一、什么是深分页?

深分页,指的是在使用 LIMIT offset, size进行分页查询时,offset(偏移量)值非常大的情况。例如:

SELECT * FROM orders ORDER BY id LIMIT 1000000, 10;

该语句的含义是:​跳过前 1000000 行,返回之后的 10 行数据

MySQL 在执行该查询时,实际上会先执行全表扫描,跳过前 1000000 行,然后再返回接下来的 10 行。当数据量很大时,跳过大量行的操作会消耗大量的 CPU 和 IO 资源,导致查询性能急剧下降。

这就是所谓的 ​深分页问题,是数据库查询性能优化中的一个经典难题。


二、深分页为何性能差?

要理解深分页为何慢,我们需要了解 MySQL 执行 LIMIT offset, size查询时的内部机制:

  1. 全表扫描或索引扫描​:MySQL 会根据查询条件以及排序规则,对数据进行排序或扫描。
  2. 跳过 offset 行​:MySQL 会先读取 offset + size 行数据,然后丢弃前 offset 行,只返回后面的 size 行。
  3. 高 offset 导致大量无效数据扫描​:当 offset 很大时,MySQL 必须扫描并跳过大量无用的行,即使你只需要其中的少量数据。

例如,当执行 LIMIT 1000000, 10时,MySQL 可能要扫描 1000010 行,然后丢弃前 1000000 行,这样的操作代价非常高昂,尤其是在数据量达到百万、千万甚至上亿级别时。


三、深分页的常见优化方案

针对深分页问题,业内已经总结出多种优化手段,下面介绍几种最为实用和常见的优化方案。


方案一:延迟关联(Deferred Join / 子查询优化)

核心思想:

先通过子查询查找出目标页所需的 ​主键 ID​(或其他索引字段),然后再通过这些 ID 去关联原表,查询完整的数据行。

原理:
  • 避免了直接在原表上进行大 offset 扫描。
  • 利用了主键或索引字段的查询高效性。
  • 只查询需要的列,减少数据传输与处理开销。
示例 SQL:

假设我们有一张订单表 orders,有字段 id, user_id, amount, create_time,并且 id是主键,我们想按 id排序做分页:

SELECT o.* 
FROM orders o
JOIN (SELECT id FROM ordersORDER BY idLIMIT 1000000, 10
) tmp ON o.id = tmp.id;
说明:
  • 子查询 SELECT id FROM orders ORDER BY id LIMIT 1000000, 10会利用主键索引快速定位到第 1000001 ~ 1000010 条记录的 ID。
  • 外层查询再通过 id关联原表,获取完整数据。
  • 由于主键索引查询非常快,整体查询性能会有显著提升。
优化扩展:

如果你的排序字段不是主键,比如是 create_time,那么可以创建联合索引 (create_time, id),并调整排序与子查询逻辑:

SELECT o.* 
FROM orders o
JOIN (SELECT id FROM ordersORDER BY create_time, idLIMIT 1000000, 10
) tmp ON o.id = tmp.id;

同时,为 create_timeid创建联合索引:

CREATE INDEX idx_createtime_id ON orders(create_time, id);

方案二:使用覆盖索引优化查询

核心思想:

如果查询的字段能够被某个索引完全覆盖,那么 MySQL 就可以直接从索引中获取数据而 ​无需回表,从而减少 IO 消耗,提高查询效率。

原理:
  • 覆盖索引(Covering Index)是指查询所需的所有字段都包含在某个索引中,因此 MySQL 可以直接从索引中返回结果,无需再到数据行中查找。
  • 但需要注意:​覆盖索引本身并不能解决深分页的 offset 问题,它更多是配合其他优化手段一起使用,比如延迟关联。
示例:

假设你查询的字段是 id, user_id, create_time,而你为这些字段建立了一个联合索引:

CREATE INDEX idx_covering ON orders(user_id, create_time, id);

如果你的查询是:

SELECT id, user_id, create_time
FROM orders
ORDER BY create_time, id
LIMIT 1000000, 10;

并且这个查询字段正好是索引 idx_covering的一部分或全部,那么 MySQL 可能只需要扫描索引而不用回表,从而提升性能。

但依然要搭配 ​延迟关联​ 或者 ​游标分页​ 才能真正解决深分页问题。


方案三:基于游标的分页(Cursor-based Pagination / Seek Method)

核心思想:

不使用传统的 LIMIT offset, size,而是基于上一页最后一条记录的某个唯一且有序的字段(通常是主键 id或时间戳 create_time),查询 ​比该字段更大(或更小)的值,从而获取下一页数据。

原理:
  • 通过记录上一页最后一条数据的 ID(或时间),下次查询时只查比该 ID 更大的数据。
  • 避免了使用 OFFSET,也就避免了扫描和跳过大量行。
  • 查询效率高,性能稳定,适合无限滚动或“加载更多”类型的分页。

示例 SQL:

假设每页 10 条数据,且按照 id正序排序:

  • 第一页:
SELECT * FROM orders
ORDER BY id
LIMIT 10;
  • 假设第一页最后一条数据的 id是 100,那么第二页:
SELECT * FROM orders
WHERE id > 100
ORDER BY id
LIMIT 10;
  • 以此类推,第 N 页只需要知道第 N-1 页最后一条的 ID 即可。
优点:
  • 查询性能极高,无需扫描和跳过任何行。
  • 适合大数据量表,尤其是用户频繁翻页的场景。
缺点:
  • 不支持随机跳页,比如用户想直接访问第 1000 页,系统无法直接定位。
  • 需要前端或客户端配合保存“上一页最后一条的 ID”。

四、如何选择合适的优化方案?

场景

推荐方案

用户可能随机访问某一页(如点击第 100 页)

延迟关联(子查询优化)

数据量大,且分页是顺序的(如“加载更多”)

游标分页(基于 ID 或时间)

查询字段多,希望减少回表

覆盖索引 + 延迟关联

排序字段无索引

优先为排序字段建立索引,再考虑上述优化

http://www.xdnf.cn/news/19010.html

相关文章:

  • SQL-Server分页查询多种方法讲解以及分页存储过程
  • Total PDF Converter多功能 PDF 批量转换工具,无水印 + 高效处理指南
  • 【Big Data】Alluxio 首个基于云的数据分析和开源AI数据编排技术
  • Zynq开发实践(FPGA之按键输入)
  • el-select多选下拉框出现了e611
  • 参数模板优化配置指南:从基础到进阶的完整解决方案
  • 学习游戏制作记录(音频的制作和使用)8.28
  • iOS开发之苹果系统包含的所有字体库
  • Node.js汉字转拼音指南:pinyin-pro全解析
  • R 语言 + 卒中 Meta 分析
  • 神经网络|(十六)概率论基础知识-伽马函数·中
  • vant Overlay 遮罩层内元素无法滚动解决方案
  • Java 大视界 -- Java 大数据在智能安防入侵检测系统中的多模态数据融合与检测精度提升(405)
  • 手写链路追踪
  • 新手向:从零开始理解百度语音识别API的Python实现
  • 跨境物流数字化转型怎么做?集运/转运系统定制,源码交付,助力企业降本增效,抢占市场先机
  • 【前端教程】JavaScript 对象与数组操作实战:从基础到优化
  • linux安装海康工业相机MVS SDK(3.0)会导致ROS的jsk插件崩溃
  • Java IO 流-详解
  • 从零开始学习单片机16
  • 循环高级(2)
  • 血缘元数据采集开放标准:OpenLineage Integrations Manually Annotated Lineage
  • 企业级数据库管理实战(二):数据库权限最小化原则的落地方法
  • 【分治法 BFS 质因数分解】P12255 [蓝桥杯 2024 国 Java B] 园丁|普及+
  • 智慧养老建设方案(PPT)
  • 开源大语言模型(Qwen3)
  • 深入探讨可视化技术如何实现安全监测
  • 【小白笔记】Visual Studio 在 2025年7月更新的功能说明(英文单词记忆)
  • 智慧工地系统:基于Java微服务与信创国产化的建筑施工数字化管理平台
  • 171-178CSS3新增