【mySQL】MySQL JOIN原理

2023-11-09

MySQL JOIN原理

先看一下实验的两张表:

表comments,总行数28856

表comments_for,总行数57,comments_id是有索引的,ID列为主键。

以上两张表是我们测试的基础,然后看一下索引,comments_for这个表comments_id是有索引的,ID为主键。

最近被公司某一开发问道JOIN了MySQL JOIN的问题,细数之下发下我对MySQL JOIN的理解并不是很深刻,所以也查看了很多文档,最后在InsideMySQL公众号看到了两篇关于JOIN的分析,感觉写的太好了,拿出来分享一下我对于JOIN的实际测试吧。下面先介绍一下MySQL关于JOIN的算法,总共分为三种(来源为InsideMySQL):

MySQL是只支持一种JOIN算法Nested-Loop Join(嵌套循环链接),不像其他商业数据库可以支持哈希链接和合并连接,不过MySQL的Nested-Loop Join(嵌套循环链接)也是有很多变种,能够帮助MySQL更高效的执行JOIN操作:

(1)Simple Nested-Loop Join(图片为InsideMySQL取来)

这个算法相对来说就是很简单了,从驱动表中取出R1匹配S表所有列,然后R2,R3,直到将R表中的所有数据匹配完,然后合并数据,可以看到这种算法要对S表进行RN次访问,虽然简单,但是相对来说开销还是太大了

(2)Index Nested-Loop Join,实现方式如下图:

索引嵌套联系由于非驱动表上有索引,所以比较的时候不再需要一条条记录进行比较,而可以通过索引来减少比较,从而加速查询。这也就是平时我们在做关联查询的时候必须要求关联字段有索引的一个主要原因。

这种算法在链接查询的时候,驱动表会根据关联字段的索引进行查找,当在索引上找到了符合的值,再回表进行查询,也就是只有当匹配到索引以后才会进行回表。至于驱动表的选择,MySQL优化器一般情况下是会选择记录数少的作为驱动表,但是当SQL特别复杂的时候不排除会出现错误选择。

在索引嵌套链接的方式下,如果非驱动表的关联键是主键的话,这样来说性能就会非常的高,如果不是主键的话,关联起来如果返回的行数很多的话,效率就会特别的低,因为要多次的回表操作。先关联索引,然后根据二级索引的主键ID进行回表的操作。这样来说的话性能相对就会很差。

(3)Block Nested-Loop Join,实现如下:

在有索引的情况下,MySQL会尝试去使用Index Nested-Loop Join算法,在有些情况下,可能Join的列就是没有索引,那么这时MySQL的选择绝对不会是最先介绍的Simple Nested-Loop Join算法,而是会优先使用Block Nested-Loop Join的算法。

Block Nested-Loop Join对比Simple Nested-Loop Join多了一个中间处理的过程,也就是join buffer,使用join buffer将驱动表的查询JOIN相关列都给缓冲到了JOIN BUFFER当中,然后批量与非驱动表进行比较,这也来实现的话,可以将多次比较合并到一次,降低了非驱动表的访问频率。也就是只需要访问一次S表。这样来说的话,就不会出现多次访问非驱动表的情况了,也只有这种情况下才会访问join buffer。

在MySQL当中,我们可以通过参数join_buffer_size来设置join buffer的值,然后再进行操作。默认情况下join_buffer_size=256K,在查找的时候MySQL会将所有的需要的列缓存到join buffer当中,包括select的列,而不是仅仅只缓存关联列。在一个有N个JOIN关联的SQL当中会在执行时候分配N-1个join buffer。

上面介绍完了,下面看一下具体的列子

(1)全表JOIN

EXPLAIN SELECT * FROM comments gc
JOIN comments_for gcf ON gc.comments_id=gcf.comments_id;

 

看一下输出信息:

 

可以看到在全表扫描的时候comments_for 作为了驱动表,此事因为关联字段是有索引的,所以对索引idx_commentsid进行了一个全索引扫描去匹配非驱动表comments ,每次能够匹配到一行。此时使用的就是Index Nested-Loop Join,通过索引进行了全表的匹配,我们可以看到因为comments_for 表的量级远小于comments ,所以说MySQL优先选择了小表comments_for 作为了驱动表。

(2)全表JOIN+筛选条件

SELECT * FROM comments gc
JOIN comments_for gcf ON gc.comments_id=gcf.comments_id
WHERE gc.comments_id =2056

 

此时使用的是Index Nested-Loop Join,先对驱动表comments 的主键进行筛选,符合一条,对非驱动表comments_for 的索引idx_commentsid进行seek匹配,最终匹配结果预计为影响一条,这样就是仅仅对非驱动表的idx_commentsid索引进行了一次访问操作,效率相对来说还是非常高的。

(3)看一下关联字段是没有索引的情况:

EXPLAIN SELECT * FROM comments gc
JOIN comments_for gcf ON gc.order_id=gcf.product_id

 

我们看一下执行计划:

从执行计划我们就可以看出,这个表JOIN就是使用了Block Nested-Loop Join来进行表关联,先把comments_for (只有57行)这个小表作为驱动表,然后将comments_for 的需要的数据缓存到JOIN buffer当中,批量对comments 表进行扫描,也就是只进行一次匹配,前提是join buffer足够大能够存下comments_for的缓存数据。

而且我们看到执行计划当中已经很明确的提示:Using where; Using join buffer (Block Nested Loop)

一般情况出现这种情况就证明我们的SQL需要优化了。

要注意的是这种情况下,MySQL也会选择Simple Nested-Loop Join这种暴力的方法,我还没搞懂他这个优化器是怎么选择的,但是一般是使用Block Nested-Loop Join,因为CBO是基于开销的,Block Nested-Loop Join的性能相对于Simple Nested-Loop Join是要好很多的。

(4)看一下left join

EXPLAIN SELECT * FROM comments gc
LEFT JOIN comments_for gcf ON gc.comments_id=gcf.comments_id

 

看一下执行计划:

这种情况,由于我们的关联字段是有索引的,所以说Index Nested-Loop Join,只不过当没有筛选条件的时候会选择第一张表作为驱动表去进行JOIN,去关联非驱动表的索引进行Index Nested-Loop Join。

如果加上筛选条件gc.comments_id =2056的话,这样就会筛选出一条对非驱动表进行Index Nested-Loop Join,这样效率是很高的。

如果是下面这种:

EXPLAIN SELECT * FROM comments_for gcf
LEFT JOIN comments gc ON gc.comments_id=gcf.comments_id
WHERE gcf.comments_id =2056

 

通过gcf表进行筛选的话,就会默认选择gcf表作为驱动表,因为很明显他进行过了筛选,匹配的条件会很少,具体可以看下执行计划:

此,join基本上已经很明了了,未完待续中,欢迎大家指出错误,我会认真改正。。。。

 

热衷于学习讨论MySQL和SQL Server,NoSQL等数据库技术,欢迎加入SQL优化群:659336691

原文:https://www.cnblogs.com/shengdimaya/p/7123069.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【mySQL】MySQL JOIN原理 的相关文章

  • 在浏览器上调试公众号网页的操作流程

    痛点说明 在实际开发过程中 公众号或者小程序开发都涉及到授权登录 我们最初原始的做法都是写好代码后 发布在测试环境中 然后再进行调试 有一个头痛的点在于如果你要验证你的想法 改动js的话 那么必须重新打包编译 打包和发布都是非常耗时的 引出

随机推荐

  • matlab大作业含代码_目标检测

    点击上方 AI算法修炼营 选择加星标或 置顶 标题以下 全是干货 来自 知乎 作者丨初识CV 来源丨https zhuanlan zhihu com p 102817180 仅作学术交流 如有侵权 请联系删文 一 数据增强 数据增强是增加深
  • Blender 2.8安装插件及如何找到打开插件

    安装插件 编辑 设置 插件 搜索 下载 安装 找到插件 安装的插件可在其下拉列表中看到所在位置 实在找不到 直接搜索
  • Java BigDecimal总结

    文章目录 Java BigDecimal总结 概述 float 和 double的问题 创建BigDecimal对象 BigDecimal valueOf 源码分析 equals 和 compareTo BigDecimal设置精度和舍入模
  • Kioptrix_Level_1-writeup

    Kioptrix Level 1 writeup 0x00 信息收集 目标机器IP 16 16 16 176 kali攻击机 16 16 16 177 nmap扫描端口服务 nmap A Pn 16 16 16 176 Starting N
  • 如何安装JDK

    Orade 公司提供了多种操作系统的 JDK 不同操作系统的 JIDK 在使用上基本类似 初学者可以根据自已使用的操作系统 从Cnacle 官方网站下载相应的JDK 安装文件 下面以64位的 Windows 10系统为的来演示 JDK 8
  • 对象的实例化

    对象的实例化 创建对象的方式 new Class的newInstance 只能调用空参的构造器 权限必须是public Constructor的newInstance Xxx 可以调用空参 带参的构造器 权限没有要求 使用clone 需要实
  • python进阶知识点汇总

    一 函数 1 函数的传参 1 值传递 将实际的参数复制一份传递给形参 函数中修改形参时 不会影响到实际参数 def a b c 2 return b c print a 10 print a 123 2 print a 2 2 引用传递 将
  • 一张图看懂区块链

    要逐步了解区块链 我们需要一步步了解如下东西 去中心化 先来考虑一个中心化集中式处理的过程 你要在某宝上买一部手机 交易流程是 你将钱打给支付宝 支付宝收款后通知卖家发货 卖家发货 你确认收货 支付宝把钱打给卖家 在这个过程中 虽然你是在和
  • Vert.x的TCP服务端和客户端配置

    Vert x系列 Vert x介绍 https blog csdn net haoranhaoshi article details 89279096 Vert x实战一 Vert x通过Http发布数据 https blog csdn n
  • 蓝桥杯2020省赛单词分析

    题目描述 小蓝正在学习一门神奇的语言 这门语言中的单词都是由小写英文字母组 成 有些单词很长 远远超过正常英文单词的长度 小蓝学了很长时间也记不住一些单词 他准备不再完全记忆这些单词 而是根据单词中哪个字母出现得最多来分辨单词 现在 请你帮
  • RHEL/CentOS 7中的网络暨network.service与NetworkManager.service详解

    在RHEL CentOS 6及以前的版本中 网络功能是通过一系列网络相关的脚本文件实现 如 etc init d network文件 及如下 sbin if 文件等 root myserver ll sbin if rwxr xr x 1
  • ESP32s3 MSC/U盘 虚拟串口

    ESP32s3 MSC U盘 虚拟串口 开发环境是 IDF4 4 芯片 esp32s3 在项目中想要用到把内部的FLASH做成U盘 但是在idf4 4中没有找到MSC相关例程 如图 1 我在网上只找到esp32s2的例程 https git
  • 英国第七批36颗互联网卫星升空

    导读 英国卫星通信公司OneWeb 36颗卫星从俄东方航天发射场点火升空 累计在轨卫星218颗 据外媒 英国卫星通信公司OneWeb 36颗卫星从俄东方航天发射场点火升空 累计在轨卫星218颗 根据OneWeb的说法 只需要再发射一批36颗
  • 解决“unable to access ‘https://github.com...”

    前提 我在操作的时候做了https授权 但是密码输入错误了 再找想改也找不到了 搞半天都会报这个错 甚至我想用秘钥的方式都不行 万恶的git 解决方法 git config global http sslVerify false 然后正常操
  • STM32F103ZET6【HAL函开发】STM32CUBEMX------USART串口实验(DMA)

    printf重定义 需要将下面的代码插入到usart c里面 USER CODE BEGIN 1 if 1 include
  • hive集群安装,连接mysql

    1 linux安装mysql 并且生成hive用户 密码为Abc 123D 权限为所有权限 请看 这点很重要 http blog csdn net qq 21383435 article details 76573955 2 我的hadoo
  • JAVA中的目录指什么_默认情况下,Java listFiles()读取目录中的文件的顺序是什么? - java...

    我编写了以下程序 该程序读取目录中的所有文件 所有文件名均由数字组成 例如10023134 txt File dir new File directoryPath File files dir listFiles for File file
  • 内存管理实战案例分析3:为何分配不出一个页面?

    微信公众号 奔跑吧linux社区本文节选自 奔跑吧Linux内核 第二版卷1第6 3 3章 1 问题描述 下面是有问题的OOM Killer内核日志 其中空闲页面为86048KB 最低警戒水位为22528KB 低水位为28160KB 读者可
  • 如何使用iMazing监督、配置器功能

    监督功能是一种移动设备管理技术 使得Apple设备所有人具有最高管理权 设备受到监督之后 仅仅可以在监督人设定的模式下运行Apple设备 如单应用运行模式 权限限制模式 禁用配对模式等 最近很火的网剧 你安全了吗 就是宣传网络安全的 利用i
  • 【mySQL】MySQL JOIN原理

    MySQL JOIN原理 先看一下实验的两张表 表comments 总行数28856 表comments for 总行数57 comments id是有索引的 ID列为主键 以上两张表是我们测试的基础 然后看一下索引 comments fo