40 mysql join 的实现

前言

join 是一个我们经常会使用到的一个 用法

我们这里 看一看各个场景下面的 join 的相关处理 

测试数据表如下, 两张测试表, tz_test, tz_test03, 表结构 一致

CREATE TABLE `tz_test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `field1` varchar(128) DEFAULT NULL,
  `field2` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `field_1_2` (`field1`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8

CREATE TABLE `tz_test_03` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `field1` varchar(128) DEFAULT NULL,
  `field2` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `field_1_2` (`field1`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8

 

tz_test 数据如下 

4a2ac7c294ea42dca097175e22fec09f.png

 

tz_test_03 数据如下 

952b3a865bf442d88b39137291a6e578.png

 

 

join条件基于主键

执行 sql 如下 ”select * from tz_test as t1 inner join tz_test_03 as t2 on t1.id = t2.id where 1 = 1”

sql 预处理的时候, 遍历各个 数据表, tz_test, tz_test_03, 将所有的字段列 merge 成为 all_fields, 传递个 qeb_tab->all_fields

这里是在迭代 tz_test, tz_test_03 的字段列表信息, 将其添加到 field_list

tz_test 的情况如下 

978ab5eb9b6d490591d58b1028d92c1d.png

 

tz_test_03 的情况如下 

03c03c5b2e664485b02e469594c3c5ed.png 

然后 field_list 传到后面的 JOIN

6b11ec18490641a28a49fda01235038e.png 

具体的 join 的实现 

91644a58fc42462fa8e08a1e4217e8e9.png 

外层循环, 基于主驱动表的循环, 这里是基于 普通的查询, 根据 主键索引, 普通索引, 全表扫描 去遍历记录, 可以看到 主驱动表 是 tz_test_03

这里填充的是 tz_test_03 的 field_list, 对应于 qep_tab->fields 中的 [3-5] 项

178e48fb25d34139a6120939e7721aa1.png

 

内层的循环是基于 外层的循环条件 来限定的查询, 假设 tz_test_03 拿到的记录为 "{"id":1, "field1":"field1", "field2":"2"}"

然后内层的循环的查询就是 "select * from tz_test where id = 1"

这里填充的是 tz_test 的 field_list, 对应于 qep_tab->fields 中的 [0-2] 项

4d457ce8d15f4ad796fd991e1bb34f38.png

 

因为是主键关联查询, 因此 info->read_record 是 join_no_more_records, qup_tab->reqd_first_record 会查询出 内层循环需要关联的 tz_test 中的记录 

ca879a63b1574c758efe596133e13823.png 

然后上面 外层循环填充了 qep_tab->fields 中的 [0-2] 项 

然后上面 内层循环填充了 qep_tab->fields 中的 [3-5] 项 

这里就是输出 qep_tab->fields 中的数据到客户端, 即为所求 

ddbf8d96c0d5466797394d400c3d691c.png

 

内层循环首次迭代基于 join_read_key 函数 

9c0acf7fa7a5430c83e5c4ec4b407ddf.png 

内层循环后续迭代基于 join_no_more_records 函数, 是直接响应 跳出 sub_select 循环

0e1930a942774203be849d860a391d45.png 

 

主驱动表的选择规则

选择的是 符合条件记录较少的表 作为主驱动表 

假设执行 sql 如下, 按照上述规则推导 会选择 tz_test_03 作为主驱动表 

select * from tz_test as t1

inner join tz_test_03 as t2 on t1.field1 = t2.field1

where t2.id = 2;

确实如此, 选择了 tz_test_03 作为主驱动表 

a571bae63e914ec883577e9ebc7b475f.png

 

假设执行 sql 如下, 按照上述规则推导 会选择 tz_test 作为主驱动表

select * from tz_test as t1

inner join tz_test_03 as t2 on t1.field1 = t2.field1

where t1.id = 2;

确实如此, 选择了 tz_test 作为主驱动表 

865607fec2a44367998a1ce84fe9cec2.png

 

 

join条件基于索引

执行 sql 如下 ”select * from tz_test as t1 inner join tz_test_03 as t2 on t1.field1 = t2.field1 where 1 = 1”

基于 field1 作为 join 条件处理类似 

只是, 这边 内层循环迭代的时候, 可能迭代多条记录, 这边是通过 内层循环表 的 field1 的索引进行迭代的 

d989b99106ea431f8bd06ec2ae97384b.png

 

内层循环首次迭代基于 join_read_always_key 函数  

60100d2fca7b4d1a9e517b4e112da71d.png 

内层循环后续迭代基于 ha_index_next_same 函数 

8afcb5e5cf5f49e191fe0344e35704a5.png 

 

join条件基于普通字段

执行 sql 如下 ”select * from tz_test as t1 inner join tz_test_03 as t2 on t1.field2 = t2.field2 where 1 = 1”

 

外层循环为 第一个 join->first_select, 走的普通的 sub_select 的流程, 基于 qep_tab->read_first_record 和 info->read_record 进行迭代 

迭代的过程中会将数据 放到 join_buffer, 主驱动表是 tz_test_03

fc1ff8c24deb4b74a9b959d3b603b8c3.png

 

基于 field2 作为 join 条件处理类似 

只是, 这里是基于 qep_tab->read_first_record 和 info->read_record 进行迭代, 然后 比较的是 join_buffer 中的 tz_test_03 表的数据 

0e135c8c7e6d432a8e0c246554906289.png

 

两层循环的比较处理是在这里, 这里 外层 while 遍历的是 tz_test 表的所有数据

for 中遍历的是 join_buffer 中的数据, 这里对应的是 tz_test_03 表中的所有数据 

然后 generate_full_extensions 中去做的是否符合 join 的条件, 以及输出 数据到客户端

ca005d7d29e54c27a11e6b532c1b7590.png

 

比如这里比较的是 tz_test 的第一条记录的 field2, 值为 “1”

和 join_buffer 中 tz_test_03 的第一条记录的 field2, 值为 “1”, 比较成功 

0fcfe4a8a8a54b9d89adb39f81af9a49.png

 

比如这里比较的是 tz_test 的第一条记录的 field2, 值为 “1”

和 join_buffer 中 tz_test_03 的第一条记录的 field2, 值为 “2”, 比较不成功 

37c6f01f5c1d45e1affe566f95f97bed.png

 

比较成功之后, 向客户端输出结果信息 

比较不成功, 迭代 下一条记录

84cc409b34a7416d855a352f4f92ce3e.png

 

 

join_buffer 和 fields 的数据是如何关联上的?

tz_test 中的数据, JOIN_CACHE_BNL::join_matching_records 的迭代中依次将记录信息填充到 qep_tab->read_record 中, 其实就是填充到 all_fields[0-2]

然后 我们看一下 join_buffer 和 fields 的数据是如何关联上的?

初始化的时候 我们看一下各个 fields 的信息

c1252d42430e49d782cc868922616137.png

 

向客户端输出结果信息的时候 各个 fields 的信息如下, 可以看到 和 初始化的时候是一致的, 是属于各个 Table 下面的各个 Field, buf 使用的是 table->record[0]

因此 上面 join_buffer 处理的时候讲数据记录填充到了 all_fields[3-5]

e151e6fc0220449d80319a4ce57cb817.png

 

join_buffer 中 field_descr 和 Table 中的 Field 关联是在 join_buffer 初始化的地方 

(*fld_ptr)->fill_cache_field 中会初始化 CACHE_FIELD 的 ptr, length, field 等等信息 

49e97ec5cb744e64ac080e836924ddf1.png

 

拷贝的地方如下, pos 为当前 join_buffer 读取到的位置, 读取之后 id 值为 2, field1 值为 ”field12”, field2 值为 2

这里会将 join_buffer 中的数据读取到 CACHE_FIELD 的各个列中, 对应的就是 Table 中的各个 Field, 也等价于填充到了 all_fields[3-5] 

cc750f45b7594f8eb46d26a4791b9f1f.png

 

其内容如下, 内容拆解如下, 主要是 四个部分, 这里对应的是记录 “{"id":"2", "field1":"field12", "field2":"2"}”

然后 紧接着是 id 为 4 的这一条记录, 再接着是 id 为 6 这条记录 

ed66d36132a242ae98cb5627f4104cc9.png

 

 

主驱动表的数据填充到 join_buffer 的地方在哪里?

主驱动表查询的每一条记录 都是直接往 join_buffer 中放 

这里显示的 qep_tab->table_ref->table_name 为 tz_test, 但是实际上查询的表示 tz_test_03

ac7a952714704c69a54665e53635ffdf.png

 

 

大数据表join条件基于主键是否有优化? 

构造 大表如下

45de28697cb14835955c8a846dfae71b.png

 

执行 sql 如下 “select * from tz_test as t1

inner join tz_test_03 as t2 on t1.id = t2.id

where 1 = 1;”

可以看到的是 查询实现是一样的, 主驱动表为的 tz_test_03, 然后 内层循环表为 tz_test

c6988e44d14040ed9375bd0dfb9d04bb.png

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/224833.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AWS攻略——创建VPC

文章目录 创建一个可以外网访问的VPCCIDR主路由表DestinationTarget 主网络ACL入站规则出站规则 子网创建EC2测试连接创建互联网网关(IGW)编辑路由表 知识点参考资料 在 《AWS攻略——VPC初识》一文中,我们在AWS默认的VPC下部署了一台可以SS…

Tomcat管理功能使用

前言 Tomcat管理功能用于对Tomcat自身以及部署在Tomcat上的应用进行管理的web应用。在默认情况下是处于禁用状态的。如果需要开启这个功能,需要配置管理用户,即配置tomcat-users.xml文件。 !!!注意:测试功…

Numpy 实现C4.5决策树

C4.5 信息增益比实现决策树 信息增益比 g R ( D , A ) g ( D , A ) H ( D ) g_{R}(D, A)\frac{g(D, A)}{H(D)} gR​(D,A)H(D)g(D,A)​ 其中, g ( D , A ) g(D,A) g(D,A)是信息增益, H ( D ) H(D) H(D)是数据集 D D D的熵 代码实现 import numpy as …

探究Spring Boot 中实现跨域的几种方式

文章目录 前言1. 使用CrossOrigin注解2. 使用WebMvcConfigurer配置3. 使用Filter配置4. 使用全局配置结束语 前言 在现代Web应用中,由于安全性和隐私的考虑,浏览器限制了从一个域向另一个域发起的跨域HTTP请求。解决这个问题的一种常见方式是实现跨域资…

webpack学习-3.管理输出

webpack学习-3.管理输出 1.简单练手2.设置 HtmlWebpackPlugin3.清理 /dist 文件夹4.manifest5.总结 1.简单练手 官网的第一个预先准备,是多入口的。 const path require(path);module.exports {entry: {index: ./src/index.js,print: ./src/print.js,},output: …

基于SSM框架家电商城系统分前后台【项目源码+数据库脚本+报告】

一、项目简介 本项目是一套基于SSM框架家电商城系统,主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本等,该项目可以直接作为bishe使用。 项目都经过严格调试,确保可以运行…

Mysql 日期函数大全

一、时间函数 (一)、获取当前时间 1、NOW() 获取当前日期和时间,在程序一开始执行便拿到时间 返回格式 YYYY-MM-DD hh:mm:ss eg: NOW() 得到 2023-12-03 12:20:02 NOW(),SLEEP(2),NOW() 得到 2023-12-03 12:20:02 | 0 | 2023-…

HeyGen推出Avatar2.0:AI视频翻译工具引领虚拟分身创作新时代

在数字创意领域迈向新的里程碑,HeyGen公司正式推出了Avatar2.0,这是一款令人惊叹的AI视频翻译工具,仅需短短5分钟,用户即可在手机上打造一个逼真的虚拟分身。HeyGen的这一最新创新标志着他们在多模态内容生成领域的持续引领地位&a…

对象数组根据布尔值true和false进行排序——js基础积累

对象数组根据布尔值true和false进行排序——js基础积累 应用场景:效果图如下:根据布尔值进行排序总结:1.true的放前面——算降序排列2.true的放后面——算升序排列 应用场景: 最近在写后台管理系统的时候,遇到一个需求…

MySQL:update set的坑

目录 一、问题描述 二、为何会出现这样的问题? 三、正确的方案 一、问题描述 我在修改mysql数据表时,看到下面的现象。 我表中原始数据如下: 执行了下面的修改,显示执行成功。 update user_function_record_entity set open_…

Android的启动模式

Android的四种启动模式:standard、singleTop、singleTask和singleInstance。 1.standard Android默认的启动模式是standard,每启动一个Activity,它都会在返回栈中入栈,并处于栈顶,不管这个返回栈是否存在这个activit…

Linux--环境变量

一.基本概念 * 环境变量 (environment variables) 一般是指在操作系统中用来指定操作系统运行环境的一些参数 * 如:我们在编写 C/C 代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但 是照样可以链接成功&am…

易基因:人早期胚胎发育的表观遗传调控(染色质重塑+组蛋白修饰+DNA甲基化)|深度综述

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 哺乳动物发育研究促进了对协调胚胎发生遗传、表观遗传和细胞过程的理解,并揭示了对人类胚胎发生特异性新见解。最近研究生成了人类早期胚胎发生的第一个表观遗传学图谱&#…

第二十一章总结

网络程序设计基础 网络程序设计编写的是与其他计算机进行通信的程序。Java 已经将网络程序所需要的元素封装成不同的类,用户只要创建这些类的对象,使用相应的方法,即使不具备有关的网络支持,也可以编写出高质量的网络通信程序。 …

Edge调用Aria2下载

一、准备工作 1、Edge浏览器:Windows系统自带或点击下载;   2、Aria2 gui:点击github下载或自行搜索下载其他版本; 二、启动Aria2 gui 解压下载的Aria2 gui到任意目录,点击“Aria2c启动器”或“AriaNg启动器”皆可。…

SLAM算法与工程实践——SLAM基本库的安装与使用(2):OpenCV库

SLAM算法与工程实践系列文章 下面是SLAM算法与工程实践系列文章的总链接,本人发表这个系列的文章链接均收录于此 SLAM算法与工程实践系列文章链接 下面是专栏地址: SLAM算法与工程实践系列专栏 文章目录 SLAM算法与工程实践系列文章SLAM算法与工程实践…

记1次nacos拉取不到配置问题

今天部署1套新的环境,nacos由运维部署完成,提供了3个端口 30820 31558 32239 启动的时候提示 [Nacos Config] config[dataIdredis.yml, groupDEFAULT_GROUP] is empty 我再三确认页面上确实已经配置好了 于是开启debug -401 Client not connected, c…

Jenkins+Maven+Gitlab+Tomcat 自动化构建打包,部署

环境准备Jenkins工具、环境、插件配置全局变量配置安装插件Deploy to containerMaven Integration plugin配置国内mvn源 创建maven项目 环境准备 1、安装服务 Jenkins工具、环境、插件配置 全局变量配置 Manage Jenkins>tools>JDK 安装 安装插件 Deploy to contai…

居民最低生活保障人数数据,2020-2022年数据,shp矢量及表格数据均有!

居民最低生活保障,是国家对共同生活的家庭成员人均收入低于当地最低生活保障标准,且符合当地最低生活保障家庭财产状况规定的家庭,给予最低生活保障。 基本信息. 数据名称: 居民最低生活保障人数数据 数据格式: shpexcel 数据几何类型: 面…

【Linux】stat命令使用

stat命令 stat命令用于显示文件的状态信息。stat命令的输出信息比ls命令的输出信息要更详细。 著者 由Michael Meskes撰写。 stat命令 -Linux手册页 语法 stat [文件或目录] 命令选项及作用 执行令 : stat --help 执行命令结果 参数 -L、 --dereference 跟…