MySQL深分页问题与优化思路

前言

大家好,这里是程序员阿亮

大家肯定都用limit进行过分页,这个分页实际上在MySQL之中是一个很笨拙的过程!很容易造成深分页问题!

一、limit深分页问题

假设你有一条这样的 SQL 语句:

sql 复制代码
SELECT * FROM orders ORDER BY create_time LIMIT 1000000, 10;

你主观上是不是认为MySQL 会直接跳到第 100 万行,然后拿出 10 条数据。但事实并非如此。

我们的MySQL会很笨拙地:

大量扫描: MySQL 必须从索引树上按顺序扫描获取 1,000,010(100万零10)条记录。

如果order by的字段是二级索引就会需要大量回表,如果没有,通过filesort也需要大量的回表查询,将100万数据放到sortbuffer里面或者临时文件进行排序在获取最后的10条!

查出这 100万零10 条完整的记录后,MySQL 会丢弃前 100 万条,只将最后的 10 条返回给你。

绝大部分的磁盘 I/O 和 CPU 算力都浪费在了那 100 万条最终要被丢弃的数据上,尤其是"回表"操作带来的大量随机磁盘读取,直接拖垮了性能。

二、优化思路

1.游标分页 / 标签分页(Seek Method)

适用场景: 移动端下拉刷新、瀑布流、或者不需要"跳页"(如直接跳转到第 100 页)的场景。

这是性能最好的分页方式。它的核心思想是:记住上一页最后一条数据的特征(通常是连续的自增 ID 或时间戳),作为下一页的查询条件。

比如说:

sql 复制代码
SELECT * FROM orders ORDER BY id LIMIT 1000000, 10;

优化后:

sql 复制代码
SELECT * FROM orders WHERE id > 1000050 ORDER BY id LIMIT 10;

这样就可以避免我们先获取前100万条数据后丢弃,直接通过索引去获取数据了!

2.子查询、延迟查询优化

适用场景: 必须保留"页码跳转"功能(比如 PC 端的传统分页组件)。

核心思想是:利用"覆盖索引"(Covering Index)极大地减少回表的开销。 我们先通过索引只查出需要的 ID,然后再用这些 ID 去关联原表获取完整数据。

优化前:

sql 复制代码
SELECT * FROM orders ORDER BY create_time LIMIT 1000000, 10;

优化后:

sql 复制代码
SELECT t1.* FROM orders t1
INNER JOIN (
    -- 这里的子查询只查主键 id,如果 create_time 有索引,就能完美命中覆盖索引,无需回表
    SELECT id FROM orders ORDER BY create_time LIMIT 1000000, 10
) t2 ON t1.id = t2.id;

通过这种方式,我们可以先在where条件建立联合索引,通过这个联合索引获取合适的ids,然后再去主键索引获取需要的10条数据,相对来说数据的开销就要小很多,因为在没有子查询的时候,我们的SQL需要获取所有的100万条数据,取出完整的行数据,然后在取最后10条

而我们的子查询则可以先获取符合条件的ids,通过我们的二级索引

然后再通过二级索引去主键索引获取数据,避免了对100万条数据的整行数据扫描。

  • 优点: 子查询中因为只查 id,避免了前 100 万条记录的回表操作,都在内存/索引中完成,性能提升非常明显。然后主查询只需要拿这 10 个 ID 回表查具体数据即可。

  • 缺点: 随着 offset 变得极其庞大(比如千万级别),子查询扫描索引的开销依然不小,只是缓解了痛点。


三、总结

实际上我们业务中使用子查询已经可以将数据在很大程度上进行性能优化了,通过减少数据量与IO来提高我们的性能,也可以通过瀑布分页来达到更高的性能需求,但是这种情况下也就不能满足跳页。

相关推荐
名字还没想好☜1 小时前
Next.js 用 Server Components 直连数据库:去掉 API 层的边界,和三条别踩的安全红线
前端·javascript·数据库·安全·react·next.js
迷迭香yy1 小时前
行业板块轮动因子实战从板块资金到因子建模的本地化Python全流程
数据库·人工智能·python
SelectDB2 小时前
抖音集团 实时数据仓库:Apache Doris / SelectDB 的技术能力与实践
数据库
SelectDB2 小时前
网易 日志与时序数据分析:Apache Doris / SelectDB 的技术能力与实践
数据库
weixin_539446783 小时前
Navicat Premium 17报缺少ODBC驱动
数据库
这个DBA有点耶3 小时前
迁移中的数据一致性挑战:如何确保百万行数据“搬得对”
mysql·架构·dba
哦虎!3 小时前
【数据库】事务
java·数据库·mysql
倔强的石头_3 小时前
时序数据库的难题不只在写入速度
数据库
IT古董5 小时前
【WMS学习笔记系列】01-需求分析
大数据·数据库
zlinear数据采集卡5 小时前
数据采集卡从入门到精通(9):分辨率与精度——16位卡不等于1/65536的精度
开发语言·数据库·fpga开发·开源·c#