MySQL对JOIN做了那些不为人知的优化《死磕MySQL系列 十七》(2)

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介: MySQL对JOIN做了那些不为人知的优化《死磕MySQL系列 十七》

二、Nested-Loop Join优化

快一个月没更文了,对Nested-Loop Join的算法还能回忆多少,SQL的执行流程大致如下:


image.png


  • 从join_test1表读取一行数据R
  • 从R中取id字段到表join_test2去查找索引a,并通过主键ID获取到满足的行
  • 取出join_test2中满足条件的行,跟R组成一行
  • 重复前三个步骤,直到表join_test1满足条件的数据扫描结束

NLJ算法的逻辑就是从驱动表取一行数据后就直接到被驱动表中做join操作,对于驱动表来说就变成了每次都匹配一个值,这时就不满足MRR优化的条件了。


通过上期文章,现在你应该知道了join_buffer在BNL算法中的作用,但在NLJ算法中并没有使用。


那想办法把驱动表的数据批量传给被驱动表进行join操作不就行了?


没错,MySQL团队在5.6版本引入了此方案,在驱动表中取出一部分数据,放到临时内存,这个临时内存就是上期的join_buffer。


那么执行流程图就会变成这样


这里需要注意没有把索引a在read_rnd_buffer中的流程画出来,如果不理解就到上文去看那副图哈!


image.png


上图中,我们依然查询了1000条数据,那么join_buffer就会存着1000条数据,如果存不下就会分段进行,直到执行结束。


对于NLJ算法的优化官方也给起来了一个名为Batched Key Access


BKA算法的启用


既然要使用MRR优化,那就要开启MRR,开启MRR的同时还要开启batched_key_access=on即可


set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

三、Block Nested-Loop Join算法优化

非常简单的优化就是在被驱动表上添加索引,这时BNL的算法就自然而然的变为BKA算法了


select * from t1 join t2 on (t1.b=t2.b) where t2.b>=1 and t2.b<=2000;


image.png


这条SQL在join_test2上只查询了2000行数据,如果你的MySQL机器对内存不那么看重的话直接给字段b加个索引即可。


反之,就需要另辟奇径了


再来复习下BNL算法的执行流程


取出join_test1的所有数据,存储join_buffer中

扫描join_test2用每行数据跟join_buffer中的数据进行对比,不满足跳过,满足存储结果集

由于被驱动表字段b是没有索引的,因此从join_buffer中读取出来的每条数据都要对join_test2进行全表扫描。


案例中join_test2表共100W数据,那么需要扫描的行数就是1000*100W = 10亿次,只需要2000条数据却要执行10亿次,这个性能可想而知。


这时,我们就可以使用奇径临时表来解决这个问题,实现思路大致如下


先把join_test2中满足条件的数据存放在临时表中tmp_join_test2中

此时临时表的数据只有条件范围的2000数据,因此是完全可以给字段b添加索引的

最后再让join_buffer跟tmp_join_test2做join操作

对应的SQL操作如下


create temporary table tmp_join_test2 (id int primary key, a int, b int, index(b))engine=innodb;
insert into tmp_join_test2 select * from join_test2 where b>=1 and b<=2000;
explain select * from join_test1 join tmp_join_test2 on (join_test1.b=tmp_join_test2.b);

扫描行数


insert 是对表join_test2进行的全表扫描,此时扫描行数为100W行


join_test1进行全表扫描一次扫描行数为1000行


每次join操作是一条数据,共计1000次,扫描行数为1000行


使用了临时表后总体扫描行数从10亿次到了100W+2000次,执行查询的结果返回预计都不到一秒时间。


总结


不管是使用BKA算法还是使用临时表都有一个共同点,那就是让被驱动表上能用上索引来主动触发BKA算法,从而提升性能。


四、Hash join

大家还记得这幅图吧!上期文章中复现Block Nested-Loop Join算法呢!结果返回了一个hash_join,上期并没有说明。


因为hash_join算法是在MySQL8.0.18才有的


image.png


hash_join生效的前提是被驱动表join的字段没有索引,在MySQL8.0.18中还有一个约束就是条件对等,例如案例中的join_test1.b=tmp_join_test2.b


但在8.0.20中取消了条件对等的约束,并全面支持non-equi-join,Semijoin,Antijoin,Left outer join/Right outer join


其实hash_join算法的实现原理很简单


驱动表中的join字段进行计算hash值

在内存中创建一个hash_table,把驱动表所有的hash值存放进去

获取被驱动表中满足条件的数据,例如join_test2中的select * from join_test2 where b>=1 and b<=20002000行数据

把这2000行数据,一行一行的跟hash_table中的数据进行对比,条件满足的数据作为结果集进行返回

可以看到hash_join算法的扫描行数跟临时表大差不差,那么为什么MySQL会默认使用hash_join这种算法呢?这个问题就要留给大家去深究了


五、总结

本期主要分享了NLJ、BNJ的算法优化


在这些优化中,hash_join在MySQL8.0.18中已经内置支持了,但低版本的还是默认为BKA算法


建议给被驱动表需要join字段加上索引,把BNL算法转为BKA或者hash_join算法


同时还给大家提供了一个临时表的方案,临时表在开发过程中是非常容易忽略的一个优化点,可以在适当的环境下学会使用临时表


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
8月前
|
SQL 缓存 关系型数据库
MySQL 慢查询是怎样优化的
本文深入解析了MySQL查询速度变慢的原因及优化策略,涵盖查询缓存、执行流程、SQL优化、执行计划分析(如EXPLAIN)、查询状态查看等内容,帮助开发者快速定位并解决慢查询问题。
357 0
|
6月前
|
缓存 关系型数据库 MySQL
降低MySQL高CPU使用率的优化策略。
通过上述方法不断地迭代改进,在实际操作中需要根据具体场景做出相对合理判断。每一步改进都需谨慎评估其变动可能导致其他方面问题,在做任何变动前建议先在测试环境验证其效果后再部署到生产环境中去。
282 6
|
7月前
|
存储 SQL 关系型数据库
MySQL 核心知识与索引优化全解析
本文系统梳理了 MySQL 的核心知识与索引优化策略。在基础概念部分,阐述了 char 与 varchar 在存储方式和性能上的差异,以及事务的 ACID 特性、并发事务问题及对应的隔离级别(MySQL 默认 REPEATABLE READ)。 索引基础部分,详解了 InnoDB 默认的 B+tree 索引结构(多路平衡树、叶子节点存数据、双向链表支持区间查询),区分了聚簇索引(数据与索引共存,唯一)和二级索引(数据与索引分离,多个),解释了回表查询的概念及优化方法,并分析了 B+tree 作为索引结构的优势(树高低、效率稳、支持区间查询)。 索引优化部分,列出了索引创建的六大原则
186 2
|
9月前
|
存储 SQL 关系型数据库
京东面试:mysql深度分页 严重影响性能?根本原因是什么?如何优化?
京东面试:mysql深度分页 严重影响性能?根本原因是什么?如何优化?
京东面试:mysql深度分页 严重影响性能?根本原因是什么?如何优化?
|
7月前
|
存储 SQL 关系型数据库
MySQL 动态分区管理:自动化与优化实践
本文介绍了如何利用 MySQL 的存储过程与事件调度器实现动态分区管理,自动化应对数据增长,提升查询性能与数据管理效率,并详细解析了分区创建、冲突避免及实际应用中的关键注意事项。
336 0
|
11月前
|
存储 关系型数据库 MySQL
MySQL细节优化:关闭大小写敏感功能的方法。
通过这种方法,你就可以成功关闭 MySQL 的大小写敏感功能,让你的数据库操作更加便捷。
922 19
|
关系型数据库 MySQL 数据库
从MySQL优化到脑力健康:技术人与效率的双重提升
聊到效率这个事,大家应该都挺有感触的吧。 不管是技术优化还是个人状态调整,怎么能更快、更省力地完成事情,都是我们每天要琢磨的事。
320 23
|
SQL 关系型数据库 MySQL
基于SQL Server / MySQL进行百万条数据过滤优化方案
对百万级别数据进行高效过滤查询,需要综合使用索引、查询优化、表分区、统计信息和视图等技术手段。通过合理的数据库设计和查询优化,可以显著提升查询性能,确保系统的高效稳定运行。
686 9
|
监控 关系型数据库 MySQL
MySQL和SQLSugar百万条数据查询分页优化
在面对百万条数据的查询时,优化MySQL和SQLSugar的分页性能是非常重要的。通过合理使用索引、调整查询语句、使用缓存以及采用高效的分页策略,可以显著提高查询效率。本文介绍的技巧和方法,可以为开发人员在数据处理和查询优化中提供有效的指导,提升系统的性能和用户体验。掌握这些技巧后,您可以在处理海量数据时更加游刃有余。
1057 9
|
算法 关系型数据库 MySQL
join查询可以⽆限叠加吗?MySQL对join查询有什么限制吗?
大家好,我是 V 哥。本文详细探讨了 MySQL 中 `JOIN` 查询的限制及其优化方法。首先,`JOIN` 查询不能无限叠加,存在资源(CPU、内存、磁盘 I/O)、性能和语法等方面的限制。过多的 `JOIN` 操作会导致数据库性能急剧下降。其次,介绍了三种常见的 `JOIN` 查询算法:嵌套循环连接(NLJ)、索引嵌套连接(INL)和基于块的嵌套循环连接(BNL),并分析了它们的触发条件和性能特点。最后,分享了优化 `JOIN` 查询的方法,包括 SQL 语句优化、索引优化、数据库配置调整等。关注 V 哥,了解更多技术干货,点赞👍支持,一起进步!
300 3

推荐镜像

更多