MySQL Join连接算法深入解析
引言
在关系型数据库中,Join操作是实现多表数据关联查询的关键手段,直接影响查询性能和资源消耗。MySQL支持多种Join算法,包括经典的索引嵌套循环连接(Index Nested-Loop Join)、块嵌套循环连接(Block Nested-Loop Join)以及针对大数据量场景优化的批量键访问(Batched Key Access,BKA)和多范围读取(Multi-Range Read,MRR)等先进技术。本文将系统介绍这些Join算法的原理、工作流程及其适用场景,重点解析BKA和MRR如何通过批量化访问和顺序读取优化I/O性能。同时,结合实际案例讲解如何通过临时表和索引优化Join执行过程,最后简要比较MySQL未支持的排序归并连接(Sort-Merge Join)算法,帮助读者全面掌握MySQL多表关联查询的优化策略与实践。
Index Nested-Loop Join(NLJ)
select * from t1 straight_join t2 on (t1.a=t2.a);
- 从表 t1 中读入一行数据 R;
- 从数据行 R 中,取出 a 字段到表 t2 里去查找;
- 取出表 t2 中满足条件的行,跟 R 组成一行,作为结果集的一部分;
- 重复执行步骤 1 到 3,直到表 t1 的末尾循环结束;
Block Nested-Loop Join(BNL)
select * from t1 straight_join t2 on (t1.a=t2.b);
BNL使用join buffer存储左表数据,左表数据太多会分段与右表进行关联。
- 把表 t1 的数据读入内存 join_buffer 中,由于我们这个语句中写的是 select *,因此是把整个表 t1 放入了内存。
- 扫描表 t2,把表 t2 中的每一行取出来,跟 join_buffer 中的数据做对比,满足 join 条件的,作为结果集的一部分返回。
Batched Key Access(BKA)
MySQL 在 5.6 版本后开始引入的 Batched Key Access(BKA)算法,BKA 算法就是对 NLJ 算法的优化。
Multi-Range Read(MRR)
MRR 优化的主要目的是尽量使用顺序读盘。
select * from t1 where a>=1 and a<=100;
未使用 MRR 查询思路:
主键索引是一棵 B+ 树,在这棵树上,每次只能根据一个主键 id 查到一行数据。因此,回表肯定是一行行搜索主键索引的。
MRR 优化的设计思路:
- 根据索引 a,定位到满足条件的记录,将 id 值放入 read_rnd_buffer 中 ;
- 将 read_rnd_buffer 中的 id 进行递增排序;
- 排序后的 id 数组,依次到主键 id 索引中查记录,并作为结果返回;
将原先的随机回表变成了顺序回表,可以提高回表效率。
如何开启 BKA
如果要使用 BKA 优化算法的话,需要开启相应配置,两个参数的作用是要启用 MRR。
set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';
BKA 工作原理
- 将外部表(左表)中相关的列放入Join Buffer中。
- 内部表(右表)批量的将Join Buffer中的索引列(索引键值)发送到Multi-Range Read(MRR)接口。
- Multi-Range Read(MRR)通过收到的Key,根据其对应的ROWID进行排序,然后再进行数据的读取操作。
- 将读取到的数据和左表的数据组合,得到结果集,最后将结果集返回给客户端。
BNL 转 BKA
select * from t1 join t2 on (t1.b=t2.b) where t2.b>=1 and t2.b<=2000;
如果使用 BNL 算法来 join 的话,这个语句的执行流程是这样的:
- 把表 t1 的所有字段取出来,存入 join_buffer 中。这个表只有 1000 行,join_buffer_size 默认值是 256k,可以完全存入。
- 扫描表 t2,取出每一行数据跟 join_buffer 中的数据进行对比。
- 如果不满足 t1.b=t2.b,则跳过。
- 如果满足 t1.b=t2.b, 再判断其他条件,也就是是否满足 t2.b 处于[1,2000]的条件,如果是,就作为结果集的一部分返回,否则跳过。
临时表 + BKA优化后的执行流程:
- 把表 t2 中满足条件的数据放在临时表 tmp_t 中;
- 为了让 join 使用 BKA 算法,给临时表 tmp_t 的字段 b 加上索引;
- 让表 t1 和 tmp_t 做 join 操作;
create temporary table temp_t(id int primary key, a int, b int, index(b))engine=innodb;
insert into temp_t select * from t2 where b>=1 and b<=2000;
select * from t1 join temp_t on (t1.b=temp_t.b);
Sort-Merge Join(SMJ)
Sort-Merge Join(SMJ)就是排序归并连接算法,也被称为Merge Join,MySQL不支持这种连接算法。SMJ可以分为排序和归并两个阶段:
- 第一阶段是排序,就是对Outer表和Inner表进行排序,排序的依据就是每条记录在连接键上的数值。
- 第二阶段就是归并,因为两张表已经按照同样的顺序排列,所以Outer表和Inner表各一次循环遍历就能完成比对工作了。
归并过程
- 比较 Outer[i] 和 Inner[j] 的连接键。
- 如果 Outer[i].id<Inner[j].id,则增加 i 的值。
- 如果 Outer[i].id>Inner[j].id,则增加 j 的值。
- 如果 Outer[i].id=Inner[j].id,说明找到了匹配的记录,将其输出到结果集,并分别增加 i 和 j 的值。
选择哪个表作为驱动表
决定哪个表做驱动表的时候,应该是两个表按照各自的条件过滤,过滤完成之后,计算参与 join 的各个字段的总数据量,数据量小的那个表,就是“小表”,应该作为驱动表。
感谢您的阅读!如果文章中有任何问题或不足之处,欢迎及时指出,您的反馈将帮助我不断改进与完善。期待与您共同探讨技术,共同进步!
相关文章:

MySQL Join连接算法深入解析
引言 在关系型数据库中,Join操作是实现多表数据关联查询的关键手段,直接影响查询性能和资源消耗。MySQL支持多种Join算法,包括经典的索引嵌套循环连接(Index Nested-Loop Join)、块嵌套循环连接(Block Nes…...
从构想到交付:专业级软开发流程详解
目录 一、软件开发生命周期(SDLC)标准化流程 1. 需求工程阶段(Requirement Engineering) 2. 系统设计阶段(System Design) 3. 开发阶段(Implementation) 4. 测试阶段&a…...
腾讯云-人脸核身+人脸识别教程
一。产品概述 慧眼人脸核身特惠活动 腾讯云慧眼人脸核身是一组对用户身份信息真实性进行验证审核的服务套件,提供人脸核身、身份信息核验、银行卡要素核验和运营商类要素核验等各类实名信息认证能力,以解决行业内大量对用户身份信息真实性核实的需求&a…...

http请求卡顿
接口有时出现卡顿,而且抓包显示有时tcp目标机器没有响应, 但nginx和java应用又没有错误日志,让人抓耳挠腮,最终还是请运维大哥帮忙,一顿操作后系统暂时无卡顿了,佩服的同时感觉疑惑到底调整了啥东…...
使用Vite打包前端Vue项目,碰到依赖包体积大,出现内存溢出的解决办法
vite.config.ts 中 方式一 使用 esbuild build: {outDir: "dist",minify: "esbuild",sourcemap: false,chunkSizeWarningLimit: 5000,rollupOptions: {experimentalLogSideEffects: false,output: {// 最小化拆分包manualChunks(id) {if (id.includes(&q…...
C语言_函数调用栈的汇编分析
在 C 语言的底层实现中,函数调用栈是程序运行时内存管理的核心机制。它不仅负责函数间的控制转移,还管理局部变量、参数传递和返回值。本文将结合 C 语言代码和 x86-64 汇编指令,深入解析函数调用栈的工作原理。 一、函数调用栈的基本概念 函数调用栈是内存中的一块后进先…...
Java Spring Boot 控制器中处理用户数据详解
目录 一、获取请求参数1.1 获取查询参数1.2 获取路径参数 二、处理表单提交2.1 处理表单数据 三、处理 JSON 数据3.1 接收 JSON 数据 四、返回 JSON 数据五、处理文件上传5.1 单文件上传5.2 多文件上传 六、总结 在 Spring Boot 应用开发中,控制器(Contr…...

vite+vue建立前端工程
参考 开始 | Vite 官方中文文档 VUE教程地址 https://cn.vuejs.org/tutorial/#step-1 第一个工程 https://blog.csdn.net/qq_35221977/article/details/137171497 脚本 chcp 65001 echo 建立vite工程 set PRO_NAMEmy-vue-appif not exist %PRO_NAME% (call npm i…...
【Docker】docker login总是报各种超时错误,导致登录不成功。
报错信息:Error response from daemon: Get “https://registry-1.docker.io/v2/”: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers).等超时错误。 解决方案:docker login总是报各种超时错…...

vue使用路由技术实现登录成功后跳转到首页
文章目录 一、概述二、使用步骤安装vue-router在src/router/index.js中创建路由器,并导出在vue应用实例中使用router声明router-view标签,展示组件内容 三、配置登录成功后跳转首页四、参考资料 一、概述 路由,决定从起点到终点的路径的进程…...

day20-线性表(链表II)
一、调试器 1.1 gdb(调试器) 在程序指定位置停顿 1.1.1 一般调试 gcc直接编译生成的是发布版(Release) gcc -g //-g调式版本,(体积大,内部有源码)(DeBug&#…...
什么是函数重载?为什么 C 不支持函数重载,而 C++能支持函数重载?
函数重载的定义 函数重载是指在同一作用域内,可以有多个同名函数,但是这些函数的参数列表(参数的个数、类型或顺序)不同。编译器会根据调用函数时传递的实际参数来确定具体调用哪个重载函数。 C不支持函数重载的原因 C语言的编译器…...
Python机器学习笔记(二十二、模型评估-交叉验证)
交叉验证(cross-validation)是一种评估泛化性能的统计学方法,它比单次划分训练集和测试集的方法更加稳定、全面。 在交叉验证中,数据被多次划分,并且需要训练多个模型。最常用的交叉验证是k折交叉验证(k-fold cross-validation),其中k是由用户指定的数字,通常取5或10…...
Python爬虫实战:获取woodo网各类免费图片,积累设计素材
1. 引言 在设计素材收集领域,woodo 网(吾道)提供了大量高质量的设计图片资源。然而,手动下载这些图片效率低下,且难以批量获取。开发自动化爬虫系统能够有效解决这一问题,但面临网站反爬机制、数据去重、并发控制等技术挑战。本文提出的爬虫系统针对 woodo 网站特点进行…...
Go语言运算符详解
文章目录 1. 算术运算符2. 关系运算符3. 逻辑运算符4. 位运算符5. 赋值运算符6. 其他运算符运算符优先级注意事项 Go语言提供了与其他语言类似的运算符,包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符等。这些运算符即可满足基本的运算需求。 1. 算…...

HTTP 连接复用机制详解
文章目录 HTTP 连接复用机制详解为什么需要连接复用?连接复用的实现方式HTTP/1.1 的 Keep-AliveHTTP/2 多路复用 HTTP/1.1 的队头阻塞问题 HTTP 连接复用机制详解 HTTP 连接复用是 HTTP/1.1 及更高版本中的核心优化机制,旨在减少 TCP 连接建立和关闭的开…...

网络协议分析 实验六 TCP和端口扫描
文章目录 实验6.1 TCP(Transfer Control Protocol)练习二 利用仿真编辑器编辑并发送TCP数据包实验6.2 UDP端口扫描实验6.3 TCP端口扫描练习一 TCP SYN扫描练习二 TCP FIN扫描 实验6.1 TCP(Transfer Control Protocol) 建立:syn,syn ack,ack 数据传送:tcp…...

Spring Web MVC————入门(2)
1,请求 我们接下来继续讲请求的部分,上期将过很多了,我们来给请求收个尾。 还记得Cookie和Seesion吗,我们在HTTP讲请求和响应报文的时候讲过,现在再给大家讲一遍,我们HTTP是无状态的协议,这次的…...
Python知识框架
一、Python基础语法 变量与数据类型 变量命名规则 基本类型:int, float, str, bool, None 复合类型:list, tuple, dict, set 类型转换与检查(type(), isinstance()) 运算符 算术运算符:, -, *, /, //, %, ** 比较…...

每日算法-250514
每日算法学习记录 (2024-05-14) 今天记录三道 LeetCode 算法题的解题思路和代码。 1. 两数之和 题目截图: 解题思路 这道题要求我们从一个整数数组中找出两个数,使它们的和等于一个给定的目标值 target,并返回这两个数的下标。 核心思路是使用 哈希…...

嵌入式培训之数据结构学习(三)gdb调试、单向链表练习、顺序表与链表对比
目录 一、gdb调试 (一)一般调试步骤与命令 (二)找段错误(无下断点的地方) (三)调试命令 二、单向链表练习 1、查找链表的中间结点(用快慢指针) 2、找出…...

虚拟机安装CentOS7网络问题
虚拟机安装CentOS7网络问题 1. 存在的问题1.1 CentOS7详细信息 2. 解决问题3.Windows下配置桥接模式 1. 存在的问题 虽然已经成功在虚拟机上安装了CentOS7,但是依旧不能上网。 1.1 CentOS7详细信息 [fanzhencentos01 ~]$ hostnamectlStatic hostname: centos01Ic…...
零基础学Java——终章:核心知识点与面试总结
Java核心知识点与面试总结 本文档旨在总结Java的核心知识点,并提供常见的面试问题与解答,帮助学习者巩固知识和准备面试。 目录 零基础学Java——大纲合集 Java基础 1. Java概述 JDK (Java Development Kit): Java开发工具包,包含Java的…...

迅为RK3588开发板安卓GPIO调用APP运行测试
将网盘上的安卓工程文件复制到 Windows 电脑上。确保工程路径中使用英文字符,不包含中文。接着,启动 Android Studio,点击“Open”按钮选择应用工程文件夹,然后点击“OK”。由于下载 Gradle 和各种 Jar 包可能需要一段时间&#x…...
在一台CentOS服务器上开启多个MySQL服务
1. 创建目录 mkdir -p /data/mysql3307/{data,tmp,logs} # 赋权 chown -R mysql:mysql /data/mysql3307 chmod -R 750 /data/mysql3307 2.修改 /etc/my.cnf ,添加[mysqld3307]实例配置组 [mysqld3307] # mysql服务的端口 port 3307 # 套接字文件存放路径 socket /…...
C#高级编程:IO和序列化
在 C# 编程中,输入输出(IO)和序列化是两个至关重要的概念,它们为数据的存储、读取以及在不同环境间的传输提供了强大的支持。无论是开发小型应用程序,还是构建复杂的企业级系统,深入理解并熟练运用 IO 和序列化技术都是必不可少的。 一、C# 中的 IO 基础 1、文件流…...

Unity 红点系统
首先明确一个,即红点系统的数据结构是一颗树,并且红点的数据结构的初始化需要放在游戏的初始化中,之后再是对应的红点UI侧的注册,对应的红点UI在销毁时需要注销对红点UI的显示回调注册,但是不销毁数据侧的红点注册 - …...

尼康VR镜头防抖模式NORMAL和ACTIVE的区别(私人笔记)
1. NORMAL 模式(常规模式) 适用场景:一般手持拍摄,比如人像、静物、风景或缓慢平移镜头(如水平追拍)等。工作特性: 补偿手抖引起的小幅度震动(比如手持时自然的不稳)&am…...
JMeter 中通过 WebSocket (WS) 协议发送和接收 Protocol Buffers (Proto) 消息
在 JMeter 中通过 WebSocket (WS) 协议发送和接收 Protocol Buffers (Proto) 消息,需要使用 JMeter WebSocket 插件,并结合 JSR223 脚本处理 Proto 的序列化和反序列化。以下是完整步骤: 1. 准备工作 1.1 安装 WebSocket 插件 下载插件&…...

从索引中排除 Elasticsearch 字段
作者:来自 Elastic Kofi Bartlett 说明如何配置 Elasticsearch 排除字段、为什么要这样做,以及应遵循的最佳实践。 更多阅读:Elasticsearch:inverted index,doc_values 及 source 想获得 Elastic 认证?了解…...