转自 http://www.cnblogs.com/shengdimaya/p/7123069.html

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基本上已经很明了了,未完待续中,欢迎大家指出错误,我会认真改正。。。。

0926mysql join的原理的更多相关文章

  1. 排序合并连接(sort merge join)的原理

    排序合并连接(sort merge join)的原理 排序合并连接(sort merge join)的原理     排序合并连接(sort merge join)       访问次数:两张表都只会访 ...

  2. Hive中Join的原理和机制

    转自:http://lxw1234.com/archives/2015/06/313.htm 笼统的说,Hive中的Join可分为Common Join(Reduce阶段完成join)和Map Joi ...

  3. MySql join匹配原理

    疑问 表:sl_sales_bill_head 订单抬头表 数据行:8474 表:sl_sales_bill          订单明细 数据行:8839 字段:SALES_BILL_NO 订单号 情 ...

  4. join方法原理

    join()方法--原理同wait方法 如果不知道保护性暂停是啥的可以参考一下上一篇文章 https://www.cnblogs.com/duizhangz/p/16222854.html join方 ...

  5. 谈谈fork/join实现原理

    害,又是一个炒冷饭的时间.fork/join是在jdk1.7中出现的一个并发工作包,其特点是可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出.从而达到多 ...

  6. mysql join 底层原理

    你知道 Sql 中 left join 的底层原理吗? 2019-09-10阅读 7130 https://cloud.tencent.com/developer/column/2367   01.前 ...

  7. 【原创】大数据基础之Spark(8)Spark中Join实现原理

    spark中join有两种,一种是RDD的join,一种是sql中的join,分别来看: 1 RDD join org.apache.spark.rdd.PairRDDFunctions /** * ...

  8. 8.深入TiDB:解析Hash Join实现原理

    本文基于 TiDB release-5.1进行分析,需要用到 Go 1.16以后的版本 我的博客地址:https://www.luozhiyun.com/archives/631 所谓 Hash Jo ...

  9. mysql join优化原理

    http://blog.itpub.net/22664653/viewspace-1692317/ http://itindex.net/detail/46772-%E4%BC%98%E5%8C%96 ...

随机推荐

  1. hdoj--5233--Gunner II(map+queue&&二分)

     Gunner II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Tot ...

  2. jquery的ajax同步异步执行

    大家先看一段简单的jquery ajax 返回值的js 代码 function getReturnAjax{  $.ajax({    type:"POST",    http:/ ...

  3. JVM命令参数指南

    1.调整最大堆内存 -Xmx 8192m 2.调整最小堆内存-Xmx 8192m3.设置虚拟机垃圾回收机制-XX:+UseG1GC4.收集垃圾日志信息-Xloggc:/D:gc.log5.OOM异常之 ...

  4. A - Fox And Snake

    Problem description Fox Ciel starts to learn programming. The first task is drawing a fox! However, ...

  5. Jenkins上Git ssh登陆配置

    1. 首先登陆linux机器 2. 切换到jenkins用户 3. 生成ssh key  ssh-keygen -t rsa -C 'amysu@acxiom.com'   4. 将生成的ssh ke ...

  6. # Nginx常见问题

    try_files的使用 按顺序检查文件是否 存在 location /{ try_files $uri $uri/ /index.php } 解析:在/下寻找$uri,如果没有找到,则去找$uri/ ...

  7. Jquery 获取父页面下指定iframe里的指定元素

    var div1=$("#iframe1",window.parent.document).contents().find("#div1");

  8. 【HTTP】如何正常关闭连接

    参考:<HTTP权威指南> 所有HTTP客户端.服务器或者代理都可以任意时刻关闭一条TCP传输连接.但是服务器永远无法确定它关闭“空闲”连接的那一刻,在线路那一头的客户端有没有数据要发送. ...

  9. usaco 过路费 Cow Toll Paths, 2009 Dec

    Description 翰家有 N 片草地,编号为 1 到 N ,彼此之间由 M 条双向道路连接,第 i 条道路连接了 Ai 和Bi,两片草地之间可能有多条道路,但没有道路会连接同一片草地,现有的道路 ...

  10. 1、Visual Studio Code安装及Hello Word

    一.环境初始化 1.下载 Visual Studio Code对应版本安装 2.下载.NET Core 2.0 SDK安装 3.安装Mono Debug   完成后界面如下:       二.创建控制 ...