背景

在使用MySQL数据库过程中,left join 基本是必用的语法,不过 join 会导致性能变慢,MySQL是如何将多张表的数据结合到一起的,了解join的运作机制,有利于写出更好性能的 SQL 。

先创建两张表,并分别放3条数据:

create table t1(m1 int, n1 char(1));
create table t2(m2 int, n2 char(1));
insert into t1 values(1 , 'a'), (2, 'b'), (3, 'c');
insert into t2 values(1 , 'b'), (2, 'c'), (3, 'd');
复制代码

笛卡尔积

t1和t2分开来查,分别都是3条。

两表合并一起查的时候,发现由6条变成了9条。

多张表关联查询的时候,就是把每张表中的记录拿出来进行匹配,然后进行组合,产生最终的结果给到客户端,

由于上面的sql,t1、t2一起查询,并没有匹配条件,因此会将两表的所有记录进行交叉组合,最终形成笛卡尔积,即:

  1. t1 的 的 1 和 t2的 1、2、3 进行组合,形成了三条记录。
  2. t1 的 的 2 和 t2的 1、2、3 进行组合,形成了三条记录。
  3. t1 的 的 3 和 t2的 1、2、3 进行组合,形成了三条记录。

最终变成了9条。

过滤条件

当使用表连接时,如果不增加任何限制条件,那么产生的笛卡尔积会非常巨大,三张表,每张表100条记录,三张表连接产生的记录就是 100 x 100 x 100 = 1000000 条,因此需要增加过滤条件,排除掉不必要的组合。

示例SQLselect * from t1, t2 where t1.m1 > 1 and t1.m1 = t2.m2 and t2.n2 < 'd'

过滤条件分为两种:

  1. 单表过滤条件: t1.m1 > 1 和 t2.n2 < 'd' 都是单表过滤条件。

  2. 两表过滤条件: t1.m1 = t2.m2 就是两表过滤条件。

连接过程

示例SQL的连接过程如下:

  1. 使用t1作为驱动表,因为t1没有任何索引,因此全表扫描 m1 > 1 的数据。

  2. 从t1中查到的每条记录,都需要去t2(被驱动表)中进行一次匹配,由于t2也没有索引,因此也需要进行全表扫描,找到匹配 t2.m2 = t1.m1 以及 t2.n2 < 'd' 的数据。

这个过程中,驱动表只需要被访问一次,但是被驱动表可能需要被访问多次,驱动表每获取到一条记录都会去被驱动表扫描一次匹配的记录联合起来。

内连接和外连接

连接分为内连接和外连接,二者的区别是,前者如果在被驱动表中找不到匹配的记录,则不会加入到最终的结果集中。

过滤条件

  1. where 子句条件,不符合where条件的记录最终都不会加入结果集中。
  2. on 子句条件,如果是内连接,效果和where等价,不符合则不会加入结果集中,如果是外连接,驱动表的记录还是会加入结果集中,被驱动表的则不会加入结果集,此时被驱动表的列以NULL值填充。

外连接

外连接又分为左外连接和右外连接,前者是选择左侧表作为驱动表,后者选择右侧表作为驱动表。

左(外)连接语法

select * from t1 left [outer] join t2 on 连接条件 [where 普通过滤条件]

t1有4,t2没有,使用左连接, t1的数据依然被查出来了,但是t2没有的则以null值填充。

右(外)连接语法

select * from t1 right [outer] join t2 on 连接条件 [where 普通过滤条件]

t2有5,t1没有,使用左连接, t5的数据依然被查出来了,但是t1没有的则以null值填充。

左外连接或者右外连接中的外是可以被省略称呼的,即称为左连接或右连接,outer 也可以从sql中被省略掉。

内连接语法

select * from t1 [inner | cross] join t2 [on 连接条件] [where 普通过滤条件];

内连接的写法比较多,以下3种处于等价状态:

  1. select * from t1 join t2
  2. select * from t1 inner join t2
  3. select * from t1 cross join t2

一般建议使用第二种方式。

可以看到内连接不符合on条件的没有被加入到结果集中:

内连接由于on子句的过滤特性,只要不满足一律过滤,因此可以不区分驱动表与被驱动表,但是外连接的on子句会将驱动表的放入结果集,因此根据要求,外连接要区分好驱动表和非驱动表。

连接原理

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

连接就是一张表作为驱动表,去匹配另一张表,步骤如下:

  1. 选取驱动表,使用与驱动表相关的过滤条件,选取代价最低的单标访问方法读取驱动表中的数据。
  2. 对步骤1中得到的每条记录都去被驱动表中根据连接条件匹配相应的记录。
  3. 如果还有第三张表,那么步骤2得到的结果成为驱动表,第三张表作为被驱动表,重复匹配过程。

三张表的嵌套循环连接,用代码表示就是三层for循环:

for item in t1for item in t2for item in t3
复制代码

使用索引加快连接速度

在嵌套循环连接中,驱动表每条记录都要去被驱动表中全表扫描一次,但是通过在被驱动表中建立索引,可以减少扫描的代价。

一般情况下,也推荐使用索引进行连接查询,如果是主键或者唯一不允许为空的情况的下,连接代价是常数级别的,即const,在连接中称为 eq_ref ,这种性能最高,

如果业务场景中,正好只需要用到索引中的列数据,尽量在查询列表和条件列表中只使用索引列,减少回表带来的代价。

Join Buffer

由于驱动表的每条记录都需要去访问一次被驱动表,这在表记录中非常大的情况下并且是无法使用索引的连接过程中,

会导致前面被驱动表刚从磁盘加载到内存中的数据,由于后续的数据加载,被释放掉以腾出地方,驱动表频繁的对被驱动表的访问,将导致大量的IO,性能会非常的差,

因此MySQL新加了一个Join Buffer,将驱动表的多条数据存入一个连接缓冲区中,扫描被驱动表时,将被驱动表的记录与Join Buffer中的多条记录进行匹配,以此减少被驱动表的IO操作,

如果Join Buffer足够大,可以存放驱动表的所有内容,那么只需要访问一次被驱动表就可以完后连接操作。

Join Buffer默认大小是256KB,可以通过启动选项或者环境变量 join_buffer_size 进行设置,在无法使用索引的情况下进行连接,机器本身内存又比较大的情况,可以调大这个参数,使的减少对被驱动表的访问,

Join Buffer会存放查询列表中的列和过滤条件中的列的数据,因此建议不要用 select * ,节约空间使的Join Buffer可以存放更多的记录。

MySQL之连接原理相关推荐

  1. mysql的NLJ_MySQL查询优化——连接以及连接原理

    在一般的项目开发中,多表查询是必不可少的.而对于存在大量数据的情况下,简单的查询已经无法满足性能需求.这就需要对表结构和SQL进行优化. 这次我们讲SQL优化的一种方式,连接查询(Join)和联合查询 ...

  2. mysql内连接运算量会增加多少_新年手打,40道经典MYSQL面试干货,速来收藏

    MySQL 面试题 1.MySQL 中有哪几种锁? 1.表级锁:开销小,加锁快:不会出现死锁:锁定粒度大,发生锁冲突的概率最 高,并发度最低. 2.行级锁:开销大,加锁慢:会出现死锁:锁定粒度最小,发 ...

  3. 架构周报| 浅析MySQL JDBC连接配置上的两个误区

    经典案例 \\ 浅析MySQL JDBC连接配置上的两个误区:相信使用MySQL的同学都配置过它的JDBC驱动,多数人会直接从哪里贴一段URL过来,然后稍作修改就上去了,对应的连接池配置也是一样的,很 ...

  4. mysql的主从复制原理与实现

    关于mysql的主从复制,之前一直在听说这个话题,一直没有实现,昨天学习了下,原来是这么回事: 既然是主从复制,那么肯定有主有从,也就说一个主数据库(一般为写库),一个从数据库(读库).主数据库更新了 ...

  5. MySQL主从复制异步原理以及搭建

    MySQL主从复制的原理: 1.首先,MySQL主库在事务提交时会把数据变更作为时间events记录在二进制日志文件binlog中:MySQL主库上的sync_binlog参数控制Binlog日志以什 ...

  6. mysql 实时聚合分析,mysql累积聚合原理与用法实例分析

    本文实例讲述了mysql累积聚合原理与用法.分享给大家供大家参考,具体如下: 累积聚合为聚合从序列内第一个元素到当前元素的数据,如为每个员工返回每月开始到现在累积的订单数量和平均订单数量 行号问题有两 ...

  7. php+sqlrelay+mysql实现连接池及读写负载均衡

    本文主要介绍sqlrelay的配置安装.通过其性能和一些具体环境的测试来帮助开发者应用在相应的场合中去应付大并发的mysql数据库连接. 什么是sqlrelay? Sqlrelay是一个开源的数据库连 ...

  8. 2.6.2.MySQL主从复制的原理

    MySQL主从复制的原理 MySQL复制技术介绍 主从复制是MySQL数据库的一种容灾备份方案:是mysql自带的功能,无需借助第三方工具,MySQL的主从复制并不是数据库磁盘上的文件直接拷贝,而是通 ...

  9. php mysql 实现原理_PHP底层和mysql的通信原理

    要清楚的几个概念: FPM进程:进程数在php-fpm.ini中设置.没有设置 max_requests ,那么进程是不会销毁的,也就是说当一个进程里面出现死循环或者内存溢出等导致进程僵死的情况出现的 ...

最新文章

  1. 记录CSS3 target伪类简介
  2. 蓝桥杯java第八届第十题--k倍区间
  3. 软件架构的数据流总结(三)
  4. 类与对象和对应方法、封装
  5. 【博士招生】卢森堡大学​SnT(CVI²)研究小组,DeepFake 检测领域
  6. Atom飞行手册翻译: 3.8 编写spec
  7. 计算机桌面图标有箭头,电脑桌面图标为什么会有一个小箭头,原来没的呀,
  8. php ajax实现上移,jquery实现标签上移、下移、置顶_jquery
  9. vscode 模拟本地服务器打开文件,设置默认浏览器为chrome
  10. centos6.5 mysql配置整理
  11. github上写简历
  12. 上海航芯 | 热敏打印机方案分享
  13. 怎么提高,芝麻信用分到750
  14. 如何在两台服务器之间传输文件
  15. JAVA计算机毕业设计毕业论文答辩管理系统Mybatis+系统+数据库+调试部署
  16. 李 小 龙 个 人 训 练 表
  17. html页面导航图标添加,vue 切换网页导航栏添加logo及标题
  18. JavaWeb旅游项目登陆功能
  19. 知识图谱基础知识之三——知识图谱的构建过程
  20. 分布式架构之网络通信

热门文章

  1. 商贸零售行业2021年投资策略:市场下沉、渠道效率升级,新品牌新业态乘风而起
  2. 基于opencv-python实现直线检测-20221127工作总结
  3. 从哪里租vps远程桌面服务器,vps远程桌面服务器租一个
  4. 哪些软装装饰让你认为是家里装修的点睛之笔?
  5. JAVA猎才优秀博主分享
  6. 订单紧急变动?交期无法确定?APS了解一下
  7. Silvaco学习笔记(六)毕设相关
  8. 专升本培训机构如何用自媒体做品牌推广
  9. 英特尔530和535哪个好_2020年终好物推荐,英特尔Evo平台认证更出彩
  10. 过滤器(1)_什么是过滤器?