mysql中连接的原理

大家好。我们在日常开发中经常会遇到多表联查的场景。今天我来为大家讲一下我们在进行多表联查时,表与表之间连接的原理。
为了方便讲解,我们先创建两个表,并填充一些数据。
在这里插入图片描述

如图所示,我创建了t1、t2两张表,每张表中插入了三条数据,我们查询一下:
在这里插入图片描述

一、连接简介

1、连接的本质

从本质上来说,连接就是把各个表中的数据取出来进行依次匹配的过程。例如,把t1和t2两个表连接起来的过程就像下图这样:
在这里插入图片描述

这个过程看起来就是把t1表的记录和t2的记录连起来组成新的更大的记录,所以这个查询过程称之为连接查询。连接查询的结果集中包含一个表中的每一条记录与另一个表中的每一条记录相互匹配的组合,像这样的结果 集就可以称之为笛卡尔积。

在MySQL中,连接查询的语法也很随意,只要在FROM语句后边跟多个表名就好了,比如我们把t1表和t2表连接起来的查询语句可以写成这样:
图片

2、连接过程简介

如果我们乐意,我们可以连接任意数量张表,但是如果没有任何限制条件的话,这些表连接起来产生的笛卡尔积可能是非常巨大的。所以在连接的时候过滤掉特定记录组合是有必要的,在连接查询中的过滤条件可以分成两种:

涉及单表的条件: 就是指只涉及到两个表中的一个表的查询条件,比如t1.m1 > 1 是只针对t1 表的过滤条件,t2.n2 < ‘d’ 是只针对 t2 表的过滤条件。

涉及两表的条件: 就是指涉及到两个表的查询条件,,比如t1.m1 = t2.m2 、 t1.n1 > t2.n2 等。

下边我们就要看一下携带过滤条件的连接查询的大致执行过程了,比方说下边这个查询语句:

SELECT * FROM t1, t2 WHERE t1.m1 > 1 AND t1.m1 = t2.m2 AND t2.n2 < 'd';

在这个查询中我们指明了这三个过滤条件:

t1.m1 > 1 
t1.m1 = t2.m2 
t2.n2 < 'd' 

那么这个连接查询的大致执行过程如下:

1、首先确定第一个需要查询的表,这个表称之为驱动表。

此处假设使用 t1 作为驱动表,那么就需要到t1 表中找满足t1.m1 > 1 的记录,因为表中的数据太少,而且我没在表上建立二级索引,所以此处查询t1表的访问方法采用全表扫描的方式执行单表查询。查询过程就如下图所示:
在这里插入图片描述

2、针对上一步骤中从驱动表产生的结果集中的每一条记录,分别需要到t2表中查找匹配的记录。

因为是根据t1表中的记录去找t2表中的记录,所以t2表也可以被称之为被驱动表。上一步从驱动表中得到了2条记录,所以需要查询2次t2表。此时涉及两个表的列的过滤条件t1.m1 = t2.m2 就派上用场了:

当t1.m1 = 2 时,过滤条件 t1.m1 = t2.m2 就相当于 t2.m2 = 2 ,所以此时 t2 表相当于有了 t2.m2 = 2 、t2.n2 < ‘d’ 这两个过滤条件,然后到 t2 表中执行单表查询。

当t1.m1 = 3 时,过滤条件 t1.m1 = t2.m2 就相当于 t2.m2 = 3 ,所以此时 t2 表相当于有了 t2.m2 = 3 、t2.n2 < ‘d’ 这两个过滤条件,然后到 t2 表中执行单表查询。所以整个连接查询的执行过程就如下图所示:

在这里插入图片描述

所以这条sql查询最后的结果只有两条符合过滤条件的记录:

在这里插入图片描述

3、内连接和外连接

我们在日常开发中,经常会遇到两表联查时,驱动表中的记录即使在被驱动表中没有匹配的记录,也仍然需要加入到结果集的情况,为了解决这个问题,就有了内连接和外连接的概念:

内连接: 驱动表中的记录在被驱动表中找不到匹配的记录,该记录不会加入到最后的结果集。

在这里插入图片描述

上边三个sql都是内连接,只是写法不同。可以看到,结果集中值包含满足 t1.n1 = ‘a’ 条件的记录。

外连接: 驱动表中的记录即使在被驱动表中没有匹配的记录,也仍然需要加入到结果集。

在MySQL 中,根据选取驱动表的不同,外连接仍然可以细分为2种:

左外连接: 选取左侧的表为驱动表。

在这里插入图片描述

我们发现左连接的结果集中包括了所有依赖表(t1)的记录。

右外连接: 选取右侧的表为驱动表。

在这里插入图片描述

我们发现左连接的结果集中包括了所有依赖表(t2)的记录。

在外连接中,WHERE过滤条件放在不同地方是有不同语义的:

WHERE子句中的过滤条件: WHERE 子句中的过滤条件就是我们平时见的那种,不论是内连接还是外连接,凡是不符合WHERE子句中的过滤条件的记录都不会被加入最后的结果集。例如:

图片

ON 子句中的过滤条件: 对于外连接的驱动表的记录来说,如果无法在被驱动表中找到匹配ON子句中的过滤条件的记录,那么该记录仍然会被加入到结果集中,对应的被驱动表记录的各个字段使用NULL值填充。 例如:
在这里插入图片描述

注意:ON子句是专门为外连接驱动表中的记录在被驱动表找不到匹配记录时应不应该把该记录加入结果集这个场景下提出的,所以如果把ON子句放到内连接中,MySQL会把它和WHERE子句一样对待,也就是说:内连接中的WHERE子句和ON子句是等价的。

二、连接的原理

上边简单介绍了一下连接、内连接、外连接这些概念,下面我们讲一讲今天的的重点–MySQL采用了什么样的算法来进行表与表之间的连接。

1、嵌套循环连接(Nested-Loop Join)

对于两表连接来说,驱动表只会被访问一遍,但被驱动表却要被访问到好多遍。具体访问几遍取决于对驱动表执行单表查询后的结果集中的记录条数。对于内连接来说,选取哪个表为驱动表都没关系,而外连接的驱动表是固定的,也就是说左(外)连接的驱动表就是左边的那个表,右(外)连接的驱动表就是右边的那个表。例如:t1表和t2表执行内连接查询的大致过程如下:

步骤1:选取驱动表,使用与驱动表相关的过滤条件,选取代价最低的单表访问方法来执行对驱动表的单表查询。

步骤2:对上一步骤中查询驱动表得到的结果集中每一条记录,都分别到被驱动表中查找匹配的记录。

通用的两表连接过程如下图所示:

在这里插入图片描述

这个过程就像是一个嵌套的循环,所以这种驱动表只访问一次,但被驱动表却可能被多次访问,访问次数取决于对驱动表执行单表查询后的结果集中的记录条数的连接执行方式称之为嵌套循环连接(Nested-Loop Join ), 这是最简单,也是最笨拙的一种连接查询算法。

2、使用索引加快连接速度

上边说到:嵌套循环连接的步骤2中可能需要访问多次被驱动表,如果访问被驱动表的方式都是全表扫描的话,那查询速度可想而知的慢。查询t2表其实就相当于一次单表扫描,我们可以利用索引来加快查询速度。

我们再来看一下上边介绍的t1表和t2表进行内连接的例子以及它的连接过程:
在这里插入图片描述在这里插入图片描述
查询驱动表t1后的结果集中有两条记录,嵌套循环连接算法需要对被驱动表查询2次。可以看到,原来的t1.m1 = t2.m2 这个涉及两个表的过滤条件在针对 t2 表做查询时关于 t1 表的条件就已经确定了,所以我们只需要单单优化对t2表的查询了,上述两个对t2表的查询语句中利用到的列是m2和n2列。我们可以进行如下尝试:

在m2 列上建立索引:因为对m2列的条件是等值查找,比如t2.m2 = 2 、 t2.m2 = 3 等,所以可能使用到 ref 的访问方法,假设使用ref 的访问方法去执行对t2表的查询的话,需要回表之后再判断t2.n2 < d 这个条件是否成立。

这里有一个比较特殊的情况,就是假设m2列是t2表的主键或者唯一二级索引列,那么使用t2.m2 = 常数 值这样的条件从t2表中查找记录的过程的代价就是常数级别的。我们知道在单表中使用主键值或者唯一二级索引列的值进行等值查找的方式称之为const,而这种在连接查询中对被驱动表使用主键值或者唯一二级索引列的值进行等值查找的查询执行方式称之为:eq_ref。

在n2 列上建立索引:涉及到的条件是t2.n2 < ‘d’ ,可能用到 range 的访问方法,假设使用 range 的访问 方法对t2 表的查询的话,需要回表之后再判断在m2列上的条件是否成立。假设m2 和n2 列上都存在索引的话,那么就需要从这两个里边儿挑一个代价更低的去执行对t2表的查询。

当 然,建立了索引不一定使用索引,只有在二级索引 + 回表的代价比全表扫描的代价更低时才会使用索引。另外,有时候连接查询的查询列表和过滤条件中可能只涉及被驱动表的部分列,而这些列都是某个索引的一部分,这种情况下即使不能使用eq_ref、ref 、ref_or_null 或者 range 这些访问方法执行对被驱动表的查询的话,也可以使用索引扫描,也就是index的访问方法来查询被驱动表。所以我们建议在真实工作中最好不要使 用*作为查询列表,最好把真实用到的列作为查询列表。

3、基于块的嵌套循环连接(Block Nested-Loop Join)

我们知道扫描一个表的过程其实是先把这个表从磁盘上加载到内存中,然后从内存中比较匹配条件是否满足。我们在开发过程中表中的数据往往成千上万条记录都是少的,几百万、几千万甚至几亿条记录的表都会有。内存里可能并不能完全存放下表中所有的记录,所以在扫描表前边记录的时候后边的记录可能还在磁盘上,等扫描到后边记录的时候可能内存不足,所以需要把前边的记录从内存中释放掉。我们前边又说过,采用嵌 套循环连接算法的两表连接过程中,被驱动表可是要被访问好多次的,如果这个被驱动表中的数据特别多而且不能使用索引进行访问,那就相当于要从磁盘上读好几次这个表,这个I/O代价就非常大了,所以我们得想办法:尽量减少访问被驱动表的次数。

上边我们讲到:驱动表结果集中有多少条记录,就得把被驱动表从磁盘上加载到内存中多少次。那么我们是不是可以在把被驱动表的记录加载到内存的时候,一次性和多条驱动表中的记录做匹配呢,这样就可以大大减少重复从磁盘上加载被驱动表的代价了。所以MySQL就有了一个 join buffer(连接缓冲区)的概念, join buffer就是执行连接查询前申请的一块固定大小的内存,先把若干条驱动表结果集中的记录装在这个join buffer中,然后开始扫描被驱动表,每一条被驱动表的记录一次性和join buffer 中的多条驱动表记录做匹配,因为匹配的过程都是在内存中完成的,所以这样可以显著减少被驱动表的I/O代价。使用join buffer 的过程如下图所示:

在这里插入图片描述
最好的情况是join buffer足够大,能容纳驱动表结果集中的所有记录,这样只需要访问一次被驱动表就可以完成连接操作了。这种加入了join buffer 的嵌套循环连接算法称之为基于块的嵌套连接(Block Nested-Loop Join)算法。

这个join buffer 的大小是可以通过启动参数或者系统变量 join_buffer_size 进行配置,默认大小为 262144字节(也就是256KB ),最小可以设置为128字节。当然,对于优化被驱动表的查询来说,最好是为被驱动表加上效率高的索引,如果实在不能使用索引,并且自己的机器的内存也比较大可以尝试调大join_buffer_size 的值来对连接查询进行优化。

另外需要注意的是,驱动表的记录并不是所有列都会被放到join buffer 中,只有查询列表中的列和过滤条件中的列才会被放到join buffer 中,所以再次提醒我们,最好不要把 * 作为查询列表,只需要把我们关心的列放到 查询列表就好了,这样还可以在join buffer中放置更多的记录。

到这里今天的内容就讲完了,欢迎大家在评论区进行讨论。最后依旧是请各位老板有钱的捧个人场,没钱的也捧个人场,谢谢各位老板!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四大运营商大流量卡测评,手机卡,物联网卡,纯流量卡

买大流量卡&#xff0c;看4个方面 优惠时间。有的只是12个月&#xff0c;24个月有优惠【可以先用一年&#xff0c;然后注销】通用流量。而不是定向流量全国通话分钟数。而不是亲情通话分钟数销户方式。是否支持随时销户&#xff0c;异地销户&#xff0c;线上销户&#xff0c;额…

火箭升空AR虚拟三维仿真演示满足客户的多样化场景需求

在航空工业的协同研发领域&#xff0c;航空AR工业装配系统公司凭借前沿的AR增强现实技术&#xff0c;正引领一场革新。通过将虚拟信息无缝融入实际环境中&#xff0c;我们为工程师、设计师和技术专家提供了前所未有的共享和审查三维模型的能力&#xff0c;极大地提升了研发效率…

使用Prometheus组件node_exporter采集linux系统的指标数据(包括cpu/内存/磁盘/网络)

一、背景 Linux系统的基本指标包括cpu、内存、磁盘、网络等&#xff0c;其中网络可以细分为带宽进出口流量、连接数和tcp监控等。 本文使用Prometheus组件node_exporter采集&#xff0c;存储在promethues&#xff0c;展示在grafana面板。 二、安装node_exporter 1、下载至本…

【数学建模】碎纸片的拼接复原

2013高教社杯全国大学生数学建模竞赛B题 问题一模型一模型二条件设立思路 问题求解 问题一 已知 d i d_i di​为第 i i i张图片图片的像素矩阵 已知 d i d_i di​都是 n ∗ m n*m n∗m二维矩阵 假设有 N N N张图片 模型一 我们认为对应位置像素匹配为 d i [ j ] [ 1 ] d k…

C++:单例模型、强制类型转换

目录 特殊类的设计不能被拷贝的类实现一个类&#xff0c;只能在堆上实例化的对象实现一个类&#xff0c;只能在栈上实例化的对象不能被继承的类 单例模式饿汉模式懒汉模式饿汉模式与懒汉模式的对比饿汉优缺点懒汉优缺点懒汉模式简化版本&#xff08;C11&#xff09; 单例释放问…

索引失效的场景有哪些?

一.概念 索引失效是指在查询时&#xff0c;数据库引擎无法使用索引来加速查询&#xff0c;从而导致查询性能下降。常见的索引失效原因有以下几种&#xff1a; 索引列没有被包含在查询条件中。如果查询条件中没有包含索引列&#xff0c;那么数据库引擎无法使用索引来加速查询。…

域提权漏洞系列分析-Zerologon漏洞分析

2020年08⽉11⽇&#xff0c;Windows官⽅发布了 NetLogon 特权提升漏洞的⻛险通告&#xff0c;该漏洞编号为CVE-2020-1472&#xff0c;漏 洞等级&#xff1a;严重&#xff0c;漏洞评分&#xff1a;10分&#xff0c;该漏洞也称为“Zerologon”&#xff0c;2020年9⽉11⽇&#xff…

WinRAR技巧:如何让多个文件压缩到更小!?

但我们要压缩多个文件的时候&#xff0c;可能会出现压缩后的体积仍然过大&#xff0c;或者需要将文件再压缩到更小&#xff0c;这种情况下&#xff0c;小编之前建议过大家将文件压缩成7z格式就会更加压缩体积。今天分享另一个技巧&#xff0c;帮助我们将多个文件压缩到更小。 …

【网络安全】勒索软件ShrinkLocker使用 windows系统安全工具BitLocker实施攻击

文章目录 威胁无不不在BitLocker 概述如何利用BitLocker进行攻击如何降低影响Win11 24H2 装机默认开启 BitLocker推荐阅读 威胁无不不在 网络攻击的形式不断发展&#xff0c;即便是合法的 Windows 安全功能也会成为黑客的攻击工具。 卡巴斯基实验室专家 发现 使用BitLocker的…

以不变应万变:在复杂世界中保持初心,坚持原则

在这个日新月异、瞬息万变的世界里&#xff0c;人情世故也显得尤为复杂。我们常常会因为忙碌的生活、工作压力以及人际关系的纠葛而感到迷茫和疲惫。在面对这些复杂局面的同时&#xff0c;如何保持内心的平静&#xff0c;坚持自己的原则&#xff0c;并在变幻莫测的环境中持续成…

ClickHouse架构概览 —— Clickhouse 架构篇(一)

文章目录 前言Clickhouse 架构简介Clickhouse 的核心抽象列和字段数据类型块表 Clickhouse 的运作过程数据插入过程数据查询过程数据更新和删除过程 前言 本文介绍了ClickHouse的整体架构&#xff0c;并对ClickHouse中的一些重要的抽象对象进行了分析。然后此基础上&#xff0…

乘风破浪,创维汽车旗舰店落户安徽

2024年5月19日&#xff0c;创维汽车宣城家奇体验中心盛大开业。宣城市委办公室副主任师典雅、市投资促进局副局长金崇学、经开区管委会副主任汤晓峰、宣城市通信局局长梁登峰、创维汽车战区总经理刘俊、创维汽车大区总监王大明等人出席此次开业盛典&#xff0c;共同见证了创维汽…

内网穿透实现公网访问自己搭建的Ollma架构的AI服务器

内网穿透实现公网访问自己搭建的Ollma架构的AI服务器 [2024年5月9号我发布一个博文关于搭建本地AI服务器的博文][https://blog.csdn.net/weixin_41905135/article/details/138588043?spm1001.2014.3001.5501]&#xff0c;今天我们内网穿透实现从公网访问我的本地AI服务器&…

全国多地入夏!对抗“高温高湿”约克VRF中央空调有妙招

随着气温飙升,北京、上海、广州、南京、天津、江苏、新疆、内蒙古部分地区等多地进入夏季状态,华北、黄淮等不少地方最高气温都超过了30℃,大街上人们短袖、短裤纷纷上阵,一派夏日炎炎的景象。 炎热夏季不仅高温频频来袭,往往还伴随着降雨带来的潮湿,天气湿热交织容易让人们身…

C++第二十弹---深入理解STL中vector的使用

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1、vector的介绍 2、vector的使用 2.1、构造函数和赋值重载 2.1.1、构造函数的介绍 2.1.2、代码演示 2.2、容量操作 2.3、遍历 2.4、增删…

【STM32】 独立看门狗配置方法

什么是看门狗 看门狗&#xff08;watchdog&#xff09;指的是一种监控系统或程序&#xff0c;用于定期检测和监控其他系统或程序的运行状态&#xff0c;并在出现问题或故障时采取相应的措施。它可以是硬件设备&#xff0c;也可以是软件程序。 在计算机领域中&#xff0c;看门狗…

【OceanBase诊断调优】—— 排查 IO 问题的方法

本文主要介绍 OceanBase 数据库 V4.x 版本中排查 IO 问题的方法以及 IO 相关的日志和视图。 IO 相关问题 -4013 内存爆、IoControl 模块内存泄漏 目前 IO 内存爆可能的原因如下&#xff0c;及相应的排查方法。 其他模块使用 IO 内存后未释放导致泄漏。 日志分析。 通过关键词…

移动云:连接未来的智慧之旅

随着数字化转型的加速&#xff0c;云服务在各行各业中的应用越来越广泛。移动云不仅提供了灵活的计算和存储资源&#xff0c;还通过创新的技术手段&#xff0c;为企业和开发者解决了许多实际问题。在这个变革的大背景下&#xff0c;移动云服务作为中国移动倾力打造的云业务品牌…

​​​【收录 Hello 算法】10.4 哈希优化策略

目录 10.4 哈希优化策略 10.4.1 线性查找&#xff1a;以时间换空间 10.4.2 哈希查找&#xff1a;以空间换时间 10.4 哈希优化策略 在算法题中&#xff0c;我们常通过将线性查找替换为哈希查找来降低算法的时间复杂度。我们借助一个算法题来加深理解。 Question 给…

vscode 插件-01基础

翻译 Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code 适用于 VS Code 的中文&#xff08;简体&#xff09;语言包 远程连接 Remote Development Remote Development是vscode的远程编程与调试的插件&#xff0c;使用这个插件可以在很多情况下代替vim…