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来提高我们的性能,也可以通过瀑布分页来达到更高的性能需求,但是这种情况下也就不能满足跳页。

相关推荐
码农阿豪18 分钟前
行标识符的抉择:深入理解数据库领域的OID与ROWID机制
数据库·oracle
不剪发的Tony老师38 分钟前
MyCLI:一个增强型MySQL命令行客户端
数据库·mysql
SHANGHAILINGEN44 分钟前
2400 万个未培养病毒重新定义病毒多样性
数据库·测序·组学
刘晨鑫11 小时前
PostgreSQL日常维护
数据库·postgresql
xiaokangzhe1 小时前
PG数据库日常应用
数据库·oracle
XDHCOM1 小时前
MySQL ER_DD_VERSION_INSTALLED报错解析,数据字典版本问题,故障修复与远程处理指南
数据库·mysql
努力的小郑1 小时前
Canal 不难,难的是用好:从接入到治理
后端·mysql·性能优化
yaoyouzhong3 小时前
MySQL 批量插入详解:快速提升大数据导入效率的实战方法
大数据·数据库·mysql
东北甜妹3 小时前
MySQL主从复制
mysql
NineData3 小时前
NineData V5.0 产品发布会:让 AI 成为数据管理的驱动力,4月16日!
数据库·人工智能·ai编程