MySQL 深分页优化

2023-09-20 23:40:05

在实际应用场景中,列表分页查询是很常见的。假设现在存在某张表,已知 ID 是主键,针对 user_name 建立了二级索引。

针对该表进行分页查询。

select * from table order by id limit offset, size;

那么同样都是获取 10 条数据,查询第一页和查询第一百页的速度一样吗?

首先先回忆下 MySQL 查询语句的执行过程:MySQL 内部可分为 server 层和存储引擎层,一条查询语句需要依次经过 连接器 -> 查询缓存 -> 解析器 & 预处理器 -> 分析器 -> 优化器 -> 执行器,执行器通过调用存储引擎层提供的接口,将一行行的数据取出,当这些数据完全符合要求(即满足查询条件),则会放到结果集中,最后再返回给客户端。

MySQL 索引查询可分为主键索引查询和非主键索引查询,其中 InnoDB 存储引擎默认采用 B+ 树索引结构:如果是主键索引,叶子节点存放完整的行数据信息,非叶子节点仅存放索引;如果是非主键索引,叶子节点存放的是主键值,若想获得完整的行数据信息,则还需要根据主键值再查询一次主键索引,即回表查询。

但不管是主键索引还是非主键索引,它们的叶子节点数据都是有序的。以主键索引为例:这些数据根据主键 ID 大小,从小到大进行排序。

基于主键索引的 limit 执行过程

select * from table order by id limit 0, 10;
select * from table order by id limit 6000000, 10;

针对第一条语句,server 层会调用 InnoDB 接口,在 InnoDB 的主键索引中获取到第 0 ~ 10 条完整的行数据,一次性返回给 server 层,并放到 server 层的结果集中,最后返回给客户端。

而在第二条语句中,offset 设置为 6000000,则会在 InnoDB 的主键索引中获取第 0 ~ 6000000 + 10 条完整的行数据,返回给 server 层后根据 offset 的数值进行丢弃,只保留后面的 size 条数据,放到 server 层的结果集中,最后返回给客户端。

可以看到,当 offset 非 0 时,server 层会从引擎层获取到很多无用的数据,而获取这些数据本身也是耗时的。

此外,当进行 select * 查询时,需要拷贝完整的行数据,而拷贝完整数据和只拷贝行数据里的部份列字段的耗时是不一样的。更何况前面 offset 条数据最后都是不要的,所以即使将完整的行数据都拷贝了也没有意义。

修改优化如下。

select * from table where id >= (select id from table order by id limit 6000000, 1) order by id limit 10;

修改后的语句,先执行子查询,从主键索引中获取到 6000001 条数据,然后 server 层丢弃前 6000000 条,只保留最后一条数据的 ID。因为只会拷贝数据行内的 ID 列,而不是拷贝数据行的所有列,所以即使数据量较大,性能还是能有显著提升。

根据子查询获取到的 ID,InnoDB 再走一次主键索引,通过 B+ 树快速定位到 id=6000000 的行数据,然后再向后取 10 条数据。

基于非主键索引的 limit 执行过程

select * from table order by user_name limit 0, 10;

上述查询语句中,server 层会调用 InnoDB 接口,在 InnoDB 的主键索引中获取到第 0 条数据对应的主键 ID 后,再回表查询对应的完整行数据,然后再返回给 server 层,server 层将其放到结果集中,最后返回给客户端。

当 offset 非 0 时,也是会丢弃前面的 offset 条数据。非主键索引的 limit 过程,比主键索引的 limit 过程,多了一步回表查询的耗时。而当 offset 数值特别大的时候,server 层的优化器可能会因为要进行大量的回表操作,从而选择全表扫描。

修改优化如下。

select * from table t1, (select id from table order by user_name limit 6000000, 10) t2 where t1.id = t2.id;

先走非主键索引取出 ID,因为只取主键值,所以不需要回表,性能会稍微快些。在返回 server 层后,同样也是丢弃 offset 条数据,只保留最后的 10 个 ID,然后再用这 10 个 ID 去和 t1 表做 ID 匹配,此时走的是主键索引,将匹配到的 10 条行数据返回,这样就绕开了之前大量的回表操作。

深分页问题

但是上面的两种优化方式,始终无法解决丢弃大量数据的问题,不管是使用 MySQL 还是借助 ES,都只能减缓问题的严重性。

针对需要获取全表数据的使用场景,可以考虑采用分批处理,将当前批次的最大 ID 作为下次筛选的条件。

伪代码如下。

start_id := 0
for {
	datas := [select * from table where id > start_id order by id limit 100]
	if len(datas) == 0 {
		break
	}
	handler(datas)
	start_id = get_max_id_from(datas)
}

针对面向用户的分页展示,可以考虑限制搜索页数范围或者限制间隔页数查询或者直接采用上下页查询的方式。

总结

  • limit offset, sizelimit size 慢,且 offset 的数值越大,SQL 的执行速度越慢
  • 当 offset 过大时,会出现深分页问题,只能通过限制查询数量或者分批查询的方式来缓解
  • 处理深分页问题,更多的应当从实际业务操作角度出发,合理地规避

参考资料

  • https://mp.weixin.qq.com/s/i6FL1iRECiWZ1CCf_juxQQ
更多推荐

Linux安全加固:保护你的服务器

🌷🍁博主猫头虎(🐅🐾)带您GotoNewWorld✨🍁🦄博客首页——🐅🐾猫头虎的博客🎐🐳《面试题大全专栏》🦕文章图文并茂🦖生动形象🐅简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》🐾学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》🐅学会Gol

Cobra眼睛蛇-强大的Golang CLI框架,快速上手的脚手架搭建项目工具,详细安装和使用

Cobra眼睛蛇-强大的GolangCLI框架,快速上手的脚手架搭建项目工具,详细安装和使用。阅读过k8s源码的同学,应该都知道k8sScheduler、kubeadm、kubelet等核心组件的命令行交互全都是通过spf13写的Cobra库来实现。本文就来介绍下Cobra的相关概念及具体用法。关于Cobra是一个用于

MySQL常用配置详解

目录一、MySQL查看配置信息二、MySQL查看服务器当前运行状态的信息三、MySQL常用配置详解1、mysql(使用mysql命令登录数据库时的默认的设置)2、client(客户端默认设置内容)3、mysqld(服务端端配置)四、配置修改演示1、修改my.cnf配置文件(window系统修改my.ini配置文件)2、

二叉树经典OJ题——【数据结构】

W...Y的主页😊代码仓库分享💕今天我们来进行二叉树的OJ练习,就是利用二叉树的前序、中序、后续以及晨序遍历的特性进行OJ训练。话不多说,来看我们的第一道题。【leetcode965.单值二叉树】OJ链接如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。只有给定的树是单值二叉树时,才返回true;否则返

Wireshark把DDoS照原形

1前言MTU、传输速度、拥塞控制,还是各种重传,TCP传输相关的核心概念:学习了RFC规范和具体的Linux实现通过案例,把这些知识灵活运用了起来这种种还是在协议规范这大框架内的讨论,默认前提就是通信两端是遵照TCP规定工作,都是君子协定。若不遵TCP规范,甚至找漏洞攻击,这种小人行为也很常见,如DDoS攻击。2NTP

正则表达式元字符

正则表达式元字符-详细说明字符说明\将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,“n"匹配字符"n”。“\n"匹配换行符。序列”\\“匹配”\“,”\(“匹配”("。^匹配输入字符串开始的位置。如果设置了RegExp对象的Multiline属性,^还会与"\n"或"\r"之后的位置匹配。$匹配输入字符

如何用Stable Diffusion模型生成个人专属创意名片?

目录1什么是二维码?2什么是扩散模型?3StableDiffusion环境搭建4开始制作创意名片结语1什么是二维码?二维码是一种用于存储和传输信息的方便而广泛使用的图像编码技术。它是由黑色方块和白色空白区域组成的二维图形,可以通过扫描设备(如智能手机)进行解码。二维码基于特定的编码标准和解码算法——其中包括错误检测和纠

如何通过简历展示自己的执行力和动力?

导语:简历是求职过程中的重要工具,通过合适的展示方式能够有效地展示自己的执行力和动力。本文将分享一些技巧,帮助您在简历中突出这两个关键能力。突出成就和项目经历:在简历中详细描述您曾经完成的项目或工作,并着重强调其中的具体成果。指出您所负责的任务,并描述您是如何通过积极的执行力完成这些任务的。例如,提及您成功地完成了某个

RHCSA_Linux 从命令行管理文件

目录一、文件命令规范:二、创建链接文件1、创建软链接文件2、创建硬链接文件三、目录操作命令1、创建目录--mkdir2、统计目录及文件的空间占用情况--du3、删除目录文件四、创建、删除普通文件1、创建普通文件2、删除普通文件五、数据流和重定向1、数据流2、重定向操作符3、输出重定向案例标准输出重定向:1>或>、1>>

2023华为OD统一考试(B卷)题库清单(持续收录中)以及考点说明

目录专栏导读2023B卷“新加题”(100分值)2023Q2100分2023Q2200分2023Q1100分2023Q1200分2022Q4100分2022Q4200分牛客练习题专栏导读本专栏收录于《华为OD机试(JAVA)真题(A卷+B卷)》。刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测

初识Spring(一)IOC

Spring框架是一个开源的Java平台,它最初是由RodJohnson编写的,并且于2003年6月首次在Apache2.0许可下发布。Spring框架的核心特性是可以用于开发任何Java应用程序,但是在JavaEE平台上构建web应用程序是需要扩展的。Spring框架的目标是使J2EE开发变得更容易使用,通过启用基于

热文推荐