解决MySQL分页优化的实现

 更新时间:2025年10月09日 09:41:14   作者:Penge666  
在后端开发中,分页查询是高频需求,但当数据量达到百万级、分页页码翻到数千页后,可能会遇到一个分页优化棘手问题,具有一定的参考价值,感兴趣的可以了解一下

在后端开发中,分页查询是高频需求,但当数据量达到百万级、分页页码翻到数千页后,你可能会遇到一个棘手问题:limit 5000000,10 这类深分页查询,响应时间突然从几十毫秒飙升到几秒甚至更久。今天就来拆解这个问题的根源,以及如何用 “覆盖索引 + 子查询” 的方案实现性能跃迁。

一、深分页查询:为什么越往后越慢?

先搞懂一个核心问题:同样是查 10 条数据,limit 10,10 很快,limit 5000000,10 却很慢,差别到底在哪?

这要从 MySQL 处理 limit offset, size 的逻辑说起:

  1. 当执行 limit 5000000,10 时,MySQL 会先扫描并排序前 5000010 条数据(offset + size);
  2. 然后丢弃前 5000000 条数据,只返回剩下的 10 条;
  3. 如果查询语句是 select *,且没有适配的索引,MySQL 还需要从磁盘读取全表数据,再进行排序 —— 这个 “扫描 + 排序 + 丢弃” 的过程,会消耗大量 CPU 和 IO 资源,数据量越大,耗时越夸张。

举个真实案例:一张 1000 万数据的商品表 tb_sku,执行 select * from tb_sku order by id limit 5000000,10,在没有优化的情况下,响应时间高达 4.8 秒;而优化后,耗时直接降到 0.08 秒,性能提升 60 倍。

二、优化核心思路:减少 “无效工作”

既然慢的根源是 “扫描了太多不需要的数据”,那优化方向就很明确:让 MySQL 只处理 “真正需要的那部分数据”,减少无效扫描和排序

这里的关键是利用 “覆盖索引” 和 “子查询” 组合:

  1. 覆盖索引:如果索引包含查询所需的所有字段,MySQL 无需回表查主数据,直接从索引获取数据即可 —— 这里我们用主键索引 id(主键默认是聚簇索引,本身有序,还能定位到主数据);
  2. 子查询优先定位主键:先用子查询 select id from tb_sku order by id limit 5000000,10,通过主键索引快速找到 “目标 10 条数据的 id”(因为主键索引有序,无需额外排序,直接定位 offset 位置);
  3. 关联主表查详情:再用找到的 id 关联主表 tb_sku,精准获取这 10 条数据的完整信息 —— 此时 MySQL 只需读取 10 条主数据,无需扫描百万级数据。

三、实操方案:优化后的 SQL 与索引配置

1. 优化后的 SQL 语句

直接上代码,核心就是 “子查询查 id + 关联查详情”:

select t.* 
from tb_sku t
inner join (
    -- 子查询:通过主键索引快速定位目标 10 条数据的 id
    select id 
    from tb_sku 
    order by id  -- 主键索引本身有序,无需额外排序
    limit 5000000, 10
) a on t.id = a.id;  -- 用 id 关联主表,精准获取详情

2. 必须配置的索引

这个方案能生效,前提是 id 是主键(或有基于 id 的索引)—— 主键默认是聚簇索引,本身就包含排序属性,所以无需额外创建索引。如果排序字段不是主键(比如按 create_time 排序),则需要创建联合索引:

-- 若按 create_time 分页,创建覆盖索引(包含排序字段和主键)
create index idx_sku_create_time on tb_sku(create_time, id);

此时子查询可以改为:

select t.* 
from tb_sku t
inner join (
    select id 
    from tb_sku 
    order by create_time 
    limit 5000000, 10
) a on t.id = a.id;

四、原理拆解:为什么这个方案这么快?

对比优化前后的执行逻辑,就能明白性能提升的关键:

阶段优化前(直接 limit 5000000,10)优化后(子查询 + 关联)
数据扫描范围扫描前 5000010 条全表数据仅扫描子查询中 10 条数据的 id(索引)
排序操作对 5000010 条数据排序主键 / 索引本身有序,无需排序
回表操作可能回表 5000010 次(若无覆盖索引)仅回表 10 次(精准关联 id)
无效数据丢弃丢弃 5000000 条数据无丢弃操作,直接获取目标数据

简单说:优化前 MySQL 在 “做无用功”(扫描、排序、丢弃大量数据),优化后只做 “必要工作”(定位 id、查 10 条详情),自然速度更快。

五、注意事项:避免踩坑

  1. 排序字段必须在索引中:如果子查询的 order by 字段不在索引里,MySQL 还是会全表排序,优化失效。比如按 price 排序,就必须创建包含 price 和 id 的索引;
  2. 关联字段用主键 / 唯一键:关联主表时,要用 id 这类主键或唯一键 —— 主键是聚簇索引,查询速度最快,避免用普通字段关联导致全表扫描;
  3. offset 过大仍有瓶颈:如果 offset 达到千万级(比如 limit 10000000,10),子查询定位 id 仍会有轻微耗时,此时建议用 “游标分页”(比如 where id > 上一页最大id limit 10),彻底避免 offset 问题;
  4. 验证执行计划:优化后用 explain 查看执行计划,确保子查询的 type 是 range 或 ref,Extra 没有 Using filesort(排序)和 Using temporary(临时表)—— 这两个关键字出现,说明索引没生效。

六、总结

深分页查询的优化,核心不是 “用更复杂的技术”,而是 “让 MySQL 少做无效工作”。本文的 “覆盖索引 + 子查询” 方案,本质是利用索引的有序性和精准定位能力,把 “百万级数据处理” 压缩到 “10 条数据处理”,实现性能质的飞跃。

如果你的项目中也有深分页场景,不妨试试这个方案 —— 从几秒到几十毫秒的提升,可能只需要改一行 SQL。

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

相关文章

  • mysql添加备注信息的实现

    mysql添加备注信息的实现

    这篇文章主要介绍了mysql添加备注信息的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • MySQL语句加锁的实现分析

    MySQL语句加锁的实现分析

    MySQL的加锁分析,一直是一个比较困难的话题。我在工作过程中,经常会有同事咨询这方面的问题。今天我们来简单谈谈这个问题
    2017-10-10
  • my.cnf参数配置实现InnoDB引擎性能优化

    my.cnf参数配置实现InnoDB引擎性能优化

    目前来说:InnoDB是为Mysql处理巨大数据量时的最大性能设计。它的CPU效率可能是任何其它基于磁盘的关系数据库引擎所不能匹敌的。在数据量大的网站或是应用中Innodb是倍受青睐的。另一方面,在数据库的复制操作中Innodb也是能保证master和slave数据一致有一定的作用。
    2017-05-05
  • 浅析MySQL的注入安全问题

    浅析MySQL的注入安全问题

    这篇文章主要介绍了浅析MySQL的注入安全问题,文中简单说道了如何避免SQL注入敞开问题的方法,需要的朋友可以参考下
    2015-05-05
  • MySql逗号拼接字符串查询的两种方法

    MySql逗号拼接字符串查询的两种方法

    这篇文章主要介绍了MySql逗号拼接字符串查询的两种方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09
  • 通过代码实例了解页面置换算法原理

    通过代码实例了解页面置换算法原理

    这篇文章主要介绍了通过代码实例了解页面置换算法原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • MySQL表分区配置入门指南

    MySQL表分区配置入门指南

    这篇文章主要为大家介绍了MySQL表分区配置入门指南,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • 远程连接服务器mysql,连接失败问题及解决

    远程连接服务器mysql,连接失败问题及解决

    本文主要介绍了如何设置MySQL远程访问权限,首先检查并开启防火墙,然后开放MySQL的3306端口,接着设置新的具有远程访问权限的账户,并并更新用户权限;最后重启MySQL,文中建议使用第二种方案,即创建新用户并赋予其远程访问权限
    2026-05-05
  • SQL中笛卡尔积的实际应用

    SQL中笛卡尔积的实际应用

    笛卡尔积算法,又称为笛卡尔积枚举法,是一种枚举算法,用于在两个或多个集合之间枚举所有可能的组合,这篇文章主要给大家介绍了关于SQL中笛卡尔积的相关资料,需要的朋友可以参考下
    2023-03-03
  • MySQL 触发器(TRIGGER)的具体使用

    MySQL 触发器(TRIGGER)的具体使用

    本文主要介绍了MySQL 触发器(TRIGGER)的具体使用,包含INSERT 触发器,UPDATE触发器和DELETE触发器这三种,具有一定的参考价值,感兴趣的可以了解一下
    2024-05-05

最新评论