MySQL-7、连接的原理

前言

前面介绍了MySQL执行查询语句其中访问方法,包括const、ref、ref_or_null、range、index、all、index_merge(索引合并)。索引合并又分三种情况,Intersection(交集)索引合并、Union(并集)索引合并、Sort-Union索引合并。

 (如果没有看前面六篇文章,不建议看此篇文章)

  传送门:

MySQL-1、InnoDB行格式

MySQL-2、InnoDB数据页

MySQL-3、索引

MySQL-4、B+树索引的使用

MySQL-5、InnoDB的表空间

MySQL-6、单表访问方法

连接的本质

我们平时经常用到连接,也就是join,常用的有inner join 、left join、rigth join、full join。(full join不同数据库语法不同)

连接就是把各个表中的记录都取出来进行依次匹配,并把匹配后的组合发送给MySQL客户端,最后再有MySQL客户端整体发送给用户。

之前说过单表查询,因为只有一个表,唯一不知道的是,如果where后面筛选条件有多个索引,到底用哪一个。那join就涉及到多表了,那到底先查哪个表以及用哪个表的索引??

说之前,先创建两个表

-- 创建学生表 students
CREATE TABLE students (student_id INT AUTO_INCREMENT PRIMARY KEY, -- 学号,主键,自增name VARCHAR(50) NOT NULL,                 -- 学生姓名,非空gender ENUM('Male', 'Female') NOT NULL,    -- 性别,枚举类型,非空birth_date DATE,                           -- 出生日期email VARCHAR(100),                        -- 邮箱phone VARCHAR(15),                         -- 电话address VARCHAR(255)                       -- 地址
);-- 创建成绩表 grades
CREATE TABLE grades (grade_id INT AUTO_INCREMENT PRIMARY KEY,   -- 成绩ID,主键,自增student_id INT,                            -- 学号,外键course_name VARCHAR(100) NOT NULL,         -- 课程名称,非空grade DECIMAL(5,2),                        -- 成绩,保留两位小数grade_date DATE                           -- 成绩日期
);-- 插入学生表数据
INSERT INTO students (name, gender, birth_date, email, phone, address) VALUES
('John Doe', 'Male', '2000-01-15', 'john.doe@example.com', '1234567890', '123 Main St'),
('Jane Smith', 'Female', '2001-02-20', 'jane.smith@example.com', '0987654321', '456 Elm St');-- 插入成绩表数据
INSERT INTO grades (student_id, course_name, grade, grade_date) VALUES
(1, 'Math', 85.50, '2024-01-10'),
(1, 'Science', 90.00, '2024-01-15'),
(2, 'Math', 88.00, '2024-01-12'),
(2, 'Science', 92.00, '2024-01-18');

比如下面一个连接查询

SELECTstudents.student_id,students.name,students.gender,students.birth_date,students.email,students.phone,students.address,grades.course_name,grades.grade,grades.grade_date
FROMstudents
LEFT JOINgrades
ONstudents.student_id = grades.student_id;

这个sql一看就知道很简单,就是一个简单的左连接查询。

连接的过程大致如下:

  • 首先确认第一个需要查询的表,这个表称为驱动表。基于上面的sql,很明显驱动表是students表。在单表执行查询语句前面一章已经介绍了,这里就不多介绍。因为没有筛选条件,所以驱动表肯定是全表扫描。
  • 从驱动表每获取到一条符合条件的记录,就需要到grades表中去查找符合条件的记录。所以grades在此次查询中是被驱动表。那被驱动表是如何查找呢,答案就是ON后面的条件。
  • 根据表数据以及上面两步可以知道,students表中有两条数据。所以就要查询grades表两次。也就是说,在两表的连接查询中,驱动表只需要访问一次,被驱动表可能需要访问多次

这里需要强调一下,在执行查询中,并不是将所有满足条件的驱动表记录先查询出来放到一个地方,然后再去被驱动表中查询。因为如果满足驱动表的数据很多,那就需要很大一片存储空间,这是不划算的。所以是每获得一条驱动表数据,就立刻到被驱动表中匹配。

内连接和外连接

内连接和外连接这是比较基础的知识,不知道的可以具体查一下。我这里稍微介绍下两者的区别:

  • 对于内连接的相关表,若驱动表中的记录在被驱动表中找不到匹配的记录,则该记录不会加入到最后的结果集中。(就是关联的表,都要满足ON后面的条件)
  • 对于外连接的相关表,即使驱动表中的记录在被驱动表中找不到匹配的记录,也仍然会加入到最后的结果集中。(就是关联的表,可以不满足ON后面的条件,只满足驱动表的条件)

外连接又包括左(外)连接和右(外)连接

左(外)连接
select * from t1 left outer join t2 on t1.xx = t2.xx;

outer可有可无。驱动表就是left join 左边的表,右边的表即是被驱动表。

右(外)连接
select * from t1 right outer join t2 on t1.xx = t2.xx;

outer可有可无。驱动表就是right join 右边的表,左边的表即是被驱动表。

内连接
select * from t1 inner join t2 on t1.xx = t2.xx;

inner可有可无,inner还可以换成cross。需要注意的是,对于内连接来说,驱动表和被驱动表是可以互换的,因为并不影响最后的查询结果

连接的原理

前面说了内连接和外连接 ,这些都是基础的知识。下面来介绍一下,连接表与表是怎样执行的。

嵌套循环连接

前面说过,驱动表只会访问一次 ,被驱动表的访问次数,是根据驱动表有多少条记录符合条件。如果有筛选条件,驱动表会根据条件,执行不同的单表访问方法。

前面的例子是连接了两张表,那假如连接三张表、四张表呢,这在工作中很常见。如下sql:

select * from t1 
inner join t2 on t1.xx = t2.xx
inner join t3 on t2.xx=t3.xx;

后面还可以连接其他表,所以上面的sql执行步骤大致如下 :

  • 先确认第一张驱动表,即是t1,获取符合t1的数据。然后确认被驱动表,既是t2,找出符合ON后面条件的数据。
  • 根据上一步中,找出t2的数据得到的结果,作为新的驱动表,t3作为被驱动表。如果后面还有连接,依次类推。

不难发现,上面的执行过程,用代码来表示就是,循环里套循环

for(int i=0...)
{for(int j=0...){for(int k=0...){}}
}

上面只是用伪代码描述一下。这种,驱动表只访问一次,但被驱动表却可能访问多次,并且次数取决于对驱动表执行单表查询后的结果集有多少条记录的连接执行方式称为 嵌套循环连接

这是最简单也是最笨拙的一种连接查询算法。那基于上面的嵌套循环连接如何优化呢。答案就是我们之前说的 索引。

使用索引加快连接速度

我们知道,嵌套循环连接是根据驱动表所查询的记录数来确定的,所以可以对驱动表或被驱动表加where条件,并且条件中最好还是索引。从而减少扫描区间,就跟我们平时优化查询一样,如果数据量特别巨大,会默认加上时间筛选条件,默认半年或者一年。

我们这里说的驱动表加筛选条件,也适用于上面三张表连接查询,对于t3表来说,t2就是驱动表。

基于块的嵌套循环连接

在实际的工作中,像t1、t2的表,数据量可能几百万,几千万。假设驱动表或被驱动表加索引也不能提高连接速度。那该怎么办呢?究其根源还是被驱动表的访问次数不能太多,执行太多次,磁盘I/O压力也很大。

所以MySQL基于减少被驱动表的访问次数 ,设计了Join Buffer(连接缓冲区)。Join Buffer就是在执行连接查询前申请一块固定大小的内存。先把若干条驱动表结果装在这个Join Buffer中,然后开始扫描被驱动表,每一条被驱动表的记录一次性地与Join Buffer中的多条驱动表记录进行匹配。由于Join Buffer是内存中的一片空间,所以Join Buffer在内存中比较就很快。

Join Buffer的嵌套循环连接算法称为 基于块的嵌套循环连接算法

Join Buffer的大下可以通过系统遍历 join_buffer_size进行配置。默认大小为256KB,最小可以设置128字节。还需要注意的是,Join Buffer中并不会存放驱动表记录的所有列,只有查询列表中列和过滤条件中的列才会放入到Join Buffer中。所以这也再次提醒我们,最好不要把 *作为查询列表。这样Join Buffer可以存放更多记录。

//查看join_buffer大小
show variables like 'join_buffer_size';

那我们怎么知道在查询中用到了哪种算法呢??

还是EXPLAIN语句,后面会做介绍,这里简单说一下,EXPLAIN中有一列叫Extra,如果该列的值中有Using join buffer就表示使用了基于块的嵌套循环连接。

总结

介绍了连接的本质,说了驱动表和被驱动表、内连接和外连接的基本知识和区别。最后再介绍了连接的原理,以及嵌套循环连接和基于块的嵌套循环连接两种算法。

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

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

相关文章

JavaWeb2-Vue

Vue 前端框架,免除原生JS中的DOM操作简化书写 (以前学过又忘了,现在才知道原来vue是前端的) 基于MVVM思想(model-view -viewModel)实现数据双向绑定 model是数据模型 view负责数据展示 即DOM 中间这个负责…

工具方法 - 如何设定自己成为什么样的人

设定自己应该成为一个什么样的人是一个个人成长和自我发现的过程。以下是一些步骤和建议,可能会对你有帮助: 1. 自我反思 了解自己: 花时间思考你的兴趣、价值观、优点和缺点。问问自己: 我喜欢做什么?我擅长什么&a…

堆排序讲解

前言 在讲堆的删除时,我们发现一步一步删除堆顶的数据,排列起来呈现出排序的规律,所以本节小编将带领大家进一步理解堆排序。 1.堆排序概念 那么什么是堆排序? 堆排序(Heap Sort)是一种基于堆数据结构的排…

GPT-4o的崛起:人工智能新纪元的开端

如何评价GPT-4o? GPT-4o的崛起:人工智能新纪元的开端 随着人工智能技术的飞速发展,GPT-4o的发布再次引起了广泛关注。作为OpenAI推出的最新一代语言模型,GPT-4o不仅在技术能力上取得了重大突破,还在应用场景和用户体验上带来了…

网络学了点socket,写个聊天室,还得改进

目录 第一版: common 服务端: 客户端 第一版问题总结: 第二版 服务端: 客户端: 改进: Windows客户端 一些小问题 还可以进行的改进 这篇文章我就先不讲网络基础的东西了,我讲讲在我进行制作我这个拉跨聊天室中遇到的问题,并写了三版代码. 第一版: common #pragm…

SpringBoot-集成TOTP

TOTP验证码提供了一种高效且安全的身份验证方法。它不仅减少了依赖短信或其他通信方式带来的成本和延时,还通过不断变换的密码增加了破解的难度。未来,随着技术的进步和对安全性要求的提高,TOTP及其衍生技术将继续发展并被更广泛地应用。TOTP…

在CSS中,可以使用`float`属性来设置元素浮动

在CSS中,可以使用float属性来设置元素浮动。float属性有三个值:left、right和none。 float: left;:将元素浮动到左侧。float: right;:将元素浮动到右侧。float: none;:取消元素的浮动(默认值)。…

代码随想录算法训练营第三十一天| 455. 分发饼干、376. 摆动序列、53. 最大子数组和

[LeetCode] 455. 分发饼干 [LeetCode] 455. 分发饼干 文章解释 [LeetCode] 455. 分发饼干 视频解释 题目: 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i]&#x…

多模态模型是什么意思(国内外的AI多模态有哪些)

在人工智能和机器学习的领域,我们经常会遇到一些专业术语,这些术语可能会让初学者感到困惑。其中,"多模态模型"就是这样一个概念。 什么是AI多模态。它是什么意思呢? 那么,多模态模型是什么意思呢&#xff1…

【Python】数据处理:SQLite操作

使用 Python 与 SQLite 进行交互非常方便。SQLite 是一个轻量级的关系数据库,Python 标准库中包含一个名为 sqlite3 的模块,可以直接使用。 import sqlite3数据库连接和管理 连接到 SQLite 数据库。如果数据库文件不存在,则创建一个新数据库…

大数据如何更好地助力乡村振兴战略的实施?

大数据可以在乡村振兴战略的实施中发挥重要的作用。以下是一些大数据如何更好地助力乡村振兴战略实施的方法: 优化资源配置:通过大数据分析,可以了解到乡村的资源分布和利用情况,帮助政府和相关机构更好地进行资源调配和规划&…

Web前端Git安装:一步步引导你走进版本控制的奇妙世界

Web前端Git安装:一步步引导你走进版本控制的奇妙世界 在Web前端开发的广阔天地中,Git作为一款强大的版本控制工具,扮演着举足轻重的角色。本文将引导你逐步完成Git的安装过程,并深入探讨其在前端开发中的重要作用。我们将从四个方…

SystemVerilog Interface Class的妙用

前言 Interface Class是在SystemVerilog 2012版本中引入的,但目前在验证中几乎很少采用,大多数验证工程师要么不知道它,要么没有看到使用它的任何好处,这使得Interface Class成为一个未被充分使用和不被重视的特性。本文将举两个…

docker镜像深入理解

大家好,本篇文章和大家聊下docker相关的话题~~ 工作中经常有关于docker镜像的问题,让人百思不解 docker镜像加载到系统中到哪里去了?docker load 加载镜像的流程是怎样的?为什么容器修改内容后,删除容器后再次开启容…

阿里云 MQTT 服务器搭建与测试(上传和下发数据finish)

一、 MQTT 概念 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于 TCP/IP协议上,由 IBM 在 1999 年发布。MQTT 最大优点在于,可以以极少的代码和有限的带宽,…

c++之旅第十弹——IO流

大家好啊,这里是c之旅第十弹,跟随我的步伐来开始这一篇的学习吧! 如果有知识性错误,欢迎各位指正!!一起加油!! 创作不易,希望大家多多支持哦! 一.流的概念&…

kNN算法-概述

所谓kNN算法就是K-nearest neigbor algorithm。这是似乎是最简单的监督机器学习算法。在训练阶段,kNN算法存储了标签训练样本数据。简单地说,就是调用训练方法时传递给它的标签训练样本会被它存储起来。 kNN算法也叫lazy learning algorithm懒惰学习算法…

计算机网络 期末复习(谢希仁版本)第8章

元文件就是一种非常小的文件,它描述或指明其他文件的一些重要信息。这里的元文件保存了有关这个音频/视频文件的信息。 10. 流式:TCP;流式实况:UDP。

Huawei 大型 WLAN 组网 AC 间漫游

AC1配置命令 <AC6005>display current-configuration # vlan batch 100 # interface Vlanif100description to_S3_CAPWAPip address 10.0.100.254 255.255.255.0 # interface GigabitEthernet0/0/1port link-type trunkport trunk allow-pass vlan 100# ip route-stati…

浅谈单臂路由

单臂路由概述 单臂路由&#xff08;router-on-a-stick&#xff09;是一种网络设计模式&#xff0c;它允许在一个物理接口上配置多个逻辑子接口&#xff0c;以实现不同VLAN&#xff08;虚拟局域网&#xff09;之间的互联互通。这种方法通常用于那些希望在一个物理接口上连接多个…