MySQL中深分页LIMIT 100000的优化方案

 更新时间:2025年11月14日 09:56:58   作者:程序员卷卷狗  
在实际项目中,分页查询是最常见的 SQL 场景之一,但随着业务数据量不断增长,我们经常会遇到深分页的请求,本文将带大家理解 MySQL 深分页的本质以及掌握高性能替代方案,感兴趣的可以了解下

一、前言:深分页是数据库最常见的性能陷阱

大家好,我是程序员卷卷狗。

在实际项目中,分页查询是最常见的 SQL 场景之一。但随着业务数据量不断增长,我们经常会遇到类似的请求:

SELECT * FROM order LIMIT 100000, 20;

看似普通的分页,却是 MySQL 性能下降最典型的原因之一。深分页会导致大量无效扫描,使数据库压力急剧上升,严重时甚至拖垮整个系统。

理解 MySQL 深分页的本质,以及掌握高性能替代方案,是后端开发必须具备的能力。

二、深分页为什么慢:MySQL 的扫描机制决定了性能上限

MySQL 在执行 LIMIT offset, size 时,后台需要先扫描 offset+size 行,再丢弃前 offset 行,最后只返回 size 行。

例如:

LIMIT 100000, 20;

实际上 MySQL 做了:

  • 扫描 100020 行
  • 丢弃前 100000 行
  • 返回最后 20 行

这意味着:OFFSET 越大,MySQL 的扫描成本越高。

深分页本质上是:大量无意义的扫描与丢弃操作导致性能变差。

三、传统的 LIMIT 深分页问题实例

假设 order 表有 500 万行。

执行:

SELECT * FROM order ORDER BY id LIMIT 3000000, 20;

执行过程如下:

  • 扫描 3000020 行
  • 丢掉 3000000 行
  • 返回 20 行

在 InnoDB 中,行是按主键组织的,因此需要大量磁盘随机读,性能极其低下。

四、深分页优化方案一:利用索引覆盖 + 子查询替代 OFFSET

最广泛使用的方法是:先查主键,再回查数据

示例:

SELECT * 
FROM order o 
JOIN (
    SELECT id 
    FROM order 
    ORDER BY id 
    LIMIT 100000, 20
) tmp ON o.id = tmp.id;

优势:

  • 子查询只扫描主键索引,成本远低于扫描整行
  • 回表只发生 20 次
  • 适用于大部分分页场景

这是后端分页中最通用的优化方式。

五、深分页优化方案二:基于主键条件的“游标式分页”

核心思想:只查询比上一页最后一条记录大的数据

示例:

SELECT * 
FROM order 
WHERE id > #{lastId} 
ORDER BY id 
LIMIT 20;

效果:

  • 不存在 OFFSET
  • 不需要无效扫描
  • 执行速度稳定
  • 延迟极低

适用于:

  • 按主键(或有序字段)分页
  • 下拉加载、滚动加载
  • 长列表查询

这是现代后端系统最推荐的分页方式。

六、深分页优化方案三:使用延迟关联减少扫描

对于关联查询,可以先通过索引获取主键,再做回表关联。

示例:

SELECT o.* 
FROM order o 
JOIN (
    SELECT id 
    FROM order 
    WHERE status = 1
    ORDER BY id
    LIMIT 100000, 20
) t ON o.id = t.id;

优点:

  • 外层只回表 20 行
  • 内层查询只扫描索引
  • 大幅降低磁盘 I/O

适用于:

  • 过滤条件多
  • 需要使用复合索引
  • 单表数据量大

七、深分页优化方案四:反向分页

如果用户想看最后几页:

SELECT * FROM order ORDER BY id DESC LIMIT 20 OFFSET 100000;

可以转换为:

SELECT * 
FROM order 
ORDER BY id ASC 
LIMIT total - 100000 - 20, 20;

减少扫描量,提升性能。

适用于:

  • 翻页至尾部页面的场景
  • 数据倾斜导致深分页的场景

八、深分页优化方案五:通过业务改造避免深分页

包括:

  • 限制最大页数
  • 滚动分页替代页码分页
  • 使用搜索条件缩减数据量
  • 使用缓存 + 分段加载
  • 使用 ES、ClickHouse 等搜索引擎替代 MySQL 深分页查询

深分页本质上是业务问题,避免深分页比优化深分页更高效。

九、面试高频问题与标准回答

问:MySQL 为什么深分页会慢?

答:LIMIT offset,size 会导致 MySQL 实际扫描 offset+size 行,再丢弃前 offset 行,随着 offset 增大,会出现大量无效扫描,磁盘 I/O 和 CPU 消耗急剧增加。

问:如何优化 LIMIT 100000,20?

答:可以通过索引覆盖查询、延迟关联、主键游标分页等方式,将 OFFSET 分离为基于主键或索引的范围过滤,从而避免大量无效扫描。

问:游标分页的原理是什么?

答:通过记录上一页的最大主键,将下一页限制为 WHERE id > lastId 的形式,使分页不再依赖 OFFSET,提高查询效率。

问:什么时候必须放弃 MySQL 分页?

答:当查询数据量非常巨大且业务允许时,可以将搜索功能迁移到 Elasticsearch 或 ClickHouse,提高深分页性能。

十、总结

深分页的性能问题来自 MySQL 扫描机制本身,而不是 SQL 写得好坏。

真正的解决方案在于:

  • 用主键分页替代 OFFSET
  • 用索引覆盖替代全表扫描
  • 用延迟关联减少回表次数
  • 用业务手段避免深分页
  • 在极端场景下采用专业搜索引擎

一句话总结:

深分页的关键不是查询更多数据,而是避免不必要的扫描。

到此这篇关于MySQL中深分页LIMIT 100000的优化方案的文章就介绍到这了,更多相关MySQL深分页内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Linux下MySQL 5.5/5.6的修改字符集编码为UTF8的方法

    Linux下MySQL 5.5/5.6的修改字符集编码为UTF8的方法

    下面小编就为大家带来一篇Linux下MySQL 5.5/5.6的修改字符集编码为UTF8的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • MySQL数据库删除数据自增ID不连续的实现示例

    MySQL数据库删除数据自增ID不连续的实现示例

    本文介绍了MySQL数据库删除数据后自增ID不连续的问题,文中通过2种方法解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-11-11
  • mysql分析sql是否成功使用索引的步骤详解

    mysql分析sql是否成功使用索引的步骤详解

    在MySQL中,可以通过使用EXPLAIN语句来分析SQL查询是否成功使用了索引,本文给大家介绍了使用EXPLAIN语句分析SQL语句是否成功使用索引的步骤,需要的朋友可以参考下
    2023-12-12
  • 关于mysql基础知识的介绍

    关于mysql基础知识的介绍

    本篇文章是对mysql的基础知识进行了详细的分析介绍,需要的朋友参考下
    2013-06-06
  • MYSQL数据插入之返回自增主键ID的方法详解

    MYSQL数据插入之返回自增主键ID的方法详解

    这篇文章主要介绍了MYSQL数据插入之返回自增主键ID的方法详解,mysql中的insert插入之后会有返回值,返回的是影响的行数,也就是说,成功插入一条数据之后返回的是1,失败则返回0,那么,很多时候我们都想要得到最后插入的id值,需要的朋友可以参考下
    2023-10-10
  • DOS命令行窗口mysql中文显示乱码问题解决方法

    DOS命令行窗口mysql中文显示乱码问题解决方法

    MySQL的默认编码是Latin1,不支持中文,如何修改MySQL的默认编码呢,下面为大家详细介绍下
    2014-05-05
  • CentOS 7中升级MySQL 5.7.23的坑与解决方法

    CentOS 7中升级MySQL 5.7.23的坑与解决方法

    我们在安装升级的时候会遇到一些问题,不过可能每个人遇到的问题不一样,多找找才能解决问题哟,下面这篇文章主要给大家介绍了关于在CentOS 7中升级MySQL 5.7.23遇到的一个坑与解决方法,需要的朋友可以参考下
    2018-10-10
  • mysql唯一性约束unique代码示例

    mysql唯一性约束unique代码示例

    这篇文章主要介绍了mysql唯一性约束unique的相关资料,需要的朋友可以参考下
    2025-11-11
  • 查看mysql语句运行时间的2种方法

    查看mysql语句运行时间的2种方法

    网站运行很慢的时候,我就特别起知道为什么这么慢,所以我查啊查,数据库绝对是很重要的一部分,里面运行的sql是绝对不能放过的。平时做项目的时候,我也会注意sql语句的书写,写出一些高效的sql来,所以我会经常测试自己写的sql语句。我把我知道的二个方法,总结一下发出来
    2014-01-01
  • MySQL中索引的创建及删除方法

    MySQL中索引的创建及删除方法

    MySQL中的索引是一种特殊的数据结构,它的主要目的是为了加快数据的检索速度,下面这篇文章主要给大家介绍了关于MySQL中索引的创建及删除的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-08-08

最新评论