本文已收录至Github,推荐阅读 Java随想录

微信公众号:Java随想录

摘要

Join是MySQL中最常见的查询操作之一,用于从多个表中获取数据并将它们组合在一起。Join算法通常使用两种基本方法:Index Nested-Loop Join(NLJ)和Block Nested-Loop Join(BNL)。本文将探讨这两种算法的工作原理,以及如何在MySQL中使用它们。

什么是Join

在MySQL中,Join是一种用于组合两个或多个表中数据的查询操作。Join操作通常基于两个表中的某些共同的列进行,这些列在两个表中都存在。MySQL支持多种类型的Join操作,如Inner Join、Left Join、Right Join、Full Join等。

Inner Join是最常见的Join类型之一。在Inner Join操作中,只有在两个表中都存在的行才会被返回。例如,如果我们有一个“customers”表和一个“orders”表,我们可以通过在这两个表中共享“customer_id”列来组合它们的数据。

SELECT *
FROM customers
INNER JOIN orders
ON customers.customer_id = orders.customer_id;

上面的查询将返回所有存在于“customers”和“orders”表中的“customer_id”列相同的行。

Index Nested-Loop Join

Index Nested-Loop Join(NLJ)算法是Join算法中最基本的算法之一。在NLJ算法中,MySQL首先选择一个表(通常是小型表)作为驱动表,并迭代该表中的每一行。然后,MySQL在第二个表中搜索匹配条件的行,这个搜索过程通常使用索引来完成。一旦找到匹配的行,MySQL将这些行组合在一起,并将它们作为结果集返回。

工作流程如图:

例如,下面这个语句:

select * from t1 straight_join t2 on (t1.a=t2.a);

在这个语句里,假设t1 是驱动表,t2是被驱动表。我们来看一下这条语句的explain结果。

可以看到,在这条语句里,被驱动表t2的字段a上有索引,join过程用上了这个索引,因此这个语句的执行流程是这样的:

  1. 从表t1中读入一行数据 R;
  2. 从数据行R中,取出a字段到表t2里去查找;
  3. 取出表t2中满足条件的行,跟R组成一行,作为结果集的一部分;
  4. 重复执行步骤1到3,直到表t1的末尾循环结束。

这个过程就跟我们写程序时的嵌套查询类似,并且可以用上被驱动表的索引,所以我们称之为“Index Nested-Loop Join”,简称NLJ

NLJ是使用上了索引的情况,如果查询条件没有使用到索引呢?

MySQL会选择使用另一个叫作“Block Nested-Loop Join”的算法,简称BNL

Block Nested-Loop Join

Block Nested Loop Join(BNL)算法与NLJ算法不同的是,BNL算法使用一个类似于缓存的机制,将表数据分成多个块,然后逐个处理这些块,以减少内存和CPU的消耗。

例如,下面这个语句:

select * from t1 straight_join t2 on (t1.a=t2.b);

字段b上是没有建立索引的。

这时候,被驱动表上没有可用的索引,算法的流程是这样的:

  1. 把表t1的数据读入线程内存join_buffer中,由于我们这个语句中写的是select *,因此是把整个表t1放入了内存;
  2. 扫描表t2,把表t2中的每一行取出来,跟join_buffer中的数据做对比,满足join条件的,作为结果集的一部分返回。

这条SQL语句的explain结果如下所示:

可以看到,在这个过程中,对表t1和t2都做了一次全表扫描,因此总的扫描行数是1100。由于join_buffer是以无序数组的方式组织的,因此对表t2中的每一行,都要做100次判断,总共需要在内存中做的判断次数是:100*1000=10万次。

虽然Block Nested-Loop Join算法是全表扫描。但是是在内存中进行的判断操作,速度上会快很多。但是性能仍然不如NLJ。

join_buffer的大小是由参数join_buffer_size设定的,默认值是256k。如果放不下表t1的所有数据话,策略很简单,就是分段放。

  1. 顺序读取数据行放入join_buffer中,直到join_buffer满了。
  2. 扫描被驱动表跟join_buffer中的数据做对比,满足join条件的,作为结果集的一部分返回。
  3. 清空join_buffer,重复上述步骤。

虽然分成多次放入join_buffer,但是判断等值条件的次数还是不变的,依然是10万次。

MRR & BKA

上篇文章里我们讲到了MRR(Multi-Range Read)。MySQL在5.6版本后引入了Batched Key Acess(BKA)算法了。这个BKA算法,其实就是对NLJ算法的优化,BKA算法正是基于MRR。

NLJ算法执行的逻辑是:从驱动表t1,一行行地取出a的值,再到被驱动表t2去做join。也就是说,对于表t2来说,每次都是匹配一个值。这时,MRR的优势就用不上了。

我们可以从表t1里一次性地多拿些行出来,,先放到一个临时内存,一起传给表t2。这个临时内存不是别人,就是join_buffer。

通过上一篇文章,我们知道join_buffer 在BNL算法里的作用,是暂存驱动表的数据。但是在NLJ算法里并没有用。那么,我们刚好就可以复用join_buffer到BKA算法中。

NLJ算法优化后的BKA算法的流程,如图所示:

图中,我在join_buffer中放入的数据是P1~P100,表示的是只会取查询需要的字段。当然,如果join buffer放不下P1~P100的所有数据,就会把这100行数据分成多段执行上图的流程。

如果要使用BKA优化算法的话,你需要在执行SQL语句之前,先设置

set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

其中,前两个参数的作用是要启用MRR。这么做的原因是,BKA算法的优化要依赖于MRR。

对于BNL,我们可以通过建立索引转为BKA。对于一些列建立索引代价太大,不好建立索引的情况,我们可以使用临时表去优化。

例如,对于这个语句:

select * from t1 join t2 on (t1.b=t2.b) where t2.b>=1 and t2.b<=2000;

使用临时表的大致思路是:

  1. 把表t2中满足条件的数据放在临时表tmp_t中;
  2. 为了让join使用BKA算法,给临时表tmp_t的字段b加上索引;
  3. 让表t1和tmp_t做join操作。

这样可以大大减少扫描的行数,提升性能。

总结

在MySQL中,不管Join使用的是NLJ还是BNL总是应该使用小表做驱动表。更准确地说,在决定哪个表做驱动表的时候,应该是两个表按照各自的条件过滤,过滤完成之后,计算参与join的各个字段的总数据量,数据量小的那个表,就是“小表”,应该作为驱动表。应当尽量避免使用BNL算法,如果确认优化器会使用BNL算法,就需要做优化。优化的常见做法是,给被驱动表的join字段加上索引,把BNL算法转成BKA算法。对于不好在索引的情况,可以基于临时表的改进方案,提前过滤出小数据添加索引。


本篇文章就到这里,感谢阅读,如果本篇博客有任何错误和建议,欢迎给我留言指正。文章持续更新,可以关注公众号第一时间阅读。

MySQL中的Join 的算法(NLJ、BNL、BKA)的更多相关文章

  1. Mysql中的Join详解

    一.Simple Nested-Loop Join(简单的嵌套循环连接) 简单来说嵌套循环连接算法就是一个双层for 循环 ,通过循环外层表的行数据,逐个与内层表的所有行数据进行比较来获取结果,当执行 ...

  2. mysql中的JOIN用法总结

    join是mysql中一个基础的关键词,一般在多表连接查询中使用,这里做一下总结 1.JOIN的语法格式 table_references: table_reference [, table_refe ...

  3. MySQL中Left Join和Right Join的理解

    虽然之前一直见过两个Join,对于其具体的含义也在参考书上读过,但是一直没有记住.现在换一种方式进行学习,改为实验方式理解. Left Join 测试表: 表结构很简单,test包括两个int字段,t ...

  4. mysql中各种join连表查询总结

    通常我们需要连接多个表查询数据,以获取想要的结果. 一.连接可以分为三类: (1) 内连接:join,inner join (2) 外连接:left join,left outer join,righ ...

  5. mysql中left join right join inner join用法分析

    mysql数据库中的关联查询,基本都会用到left join,right join,inner join等查询方式,今天来说说这三种用法的区别 1.创建表test1,test2,插入测试数据 #创建表 ...

  6. Mysql中eft join、right join、inner join的区别

    left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录inner join(等值连接) 只 ...

  7. mysql中left join ,right join 以及inner join 比较

    下面是例子分析表A记录如下: aID        aNum 1           a20050111 2           a20050112 3           a20050113 4   ...

  8. (转) mysql中left join,right join,inner join的区别

    转自:https://blog.csdn.net/qq_35975416/article/details/78842958 sql查询中有一个非常重要的环节就是表的关联查询,一般使用left join ...

  9. mysql中left join中的on条件 和 where条件区别

    需要知道sql中关键字的执行顺序. FROM-> ON->JOIN-> WHERE->GROUP BY-> HAVING->SELECT-> DISTINCT ...

  10. Mysql中Left Join 与Right Join 与 Inner Join 与 Full Join的区别

    看看Left Join 与Right Join 与 Inner Join 与 Full Join对表进行操作后得到的结果. 在数据库中新建两张表,并插入要测试的数据. 新建表: USE [Test] ...

随机推荐

  1. 使用scrollIntoView 使某元素滚动到指定位置

    var el = document.getElementById('A'); el.scrollIntoView('true'); 知识: element.scrollIntoView(); // 使 ...

  2. LockSupport实现线程同步

    public class LockSupport01 { static Thread t1 = null, t2 = null; public static void main(String[] ar ...

  3. vs调试导入功能时莫名自动结束调试

    新装了vs2022,默认下图所示的地方打勾,导致调试文件导入功能时触发了自动结束调试,真是坑爹~~

  4. iphone 熄屏黑屏录像方法-取证拍摄-自带功能

    iphone 有个旁白模式是为了残疾盲人的只听模式. 1.在 设置 - 辅助功能 - 辅助功能快捷键 - 选旁白 ,这样按三下电源键进入/退出旁白模式. 2.把声音调没,这样旁白就不会发出朗读. 3. ...

  5. sap shift语法

    shift  xxx LEFT DELETING LEADING / RIGHT DELETING TRAILING mask 语法. xxx中的第一或最后一个字符出现在mask中,则xxx左移或者右 ...

  6. LoadRunner——创建场景及运行场景(三)

    1. 创建场景 场景:用户并发访问的策略,包含用户数.加载用户的时间等 启动第二个组件 : 控制台 (controller) 方式1: 开始->所有程序->HPLoadRunner-> ...

  7. 集训第二周计划:把cf近期的div2除了最后一题给切完

    太菜了太菜了,弄个训练计划. 晚上没事干的时候我想把博客园皮肤改一下,搜着搜着不知道怎么回事点进去一些竞赛选手的博客,比如这个 https://www.cnblogs.com/soda-ma/p/13 ...

  8. 如何解决 Iterative 半监督训练 在 ASR 训练中难以落地的问题丨RTC Dev Meetup

    前言 「语音处理」是实时互动领域中非常重要的一个场景,在声网发起的「RTC Dev Meetup丨语音处理在实时互动领域的技术实践和应用」活动中,来自微软亚洲研究院.声网.数美科技的技术专家,围绕该话 ...

  9. Python学习之爬虫

    又被老师要求去搞Python ,曰,,下午回顾了一下Python的基础知识,写了个爬取图片的程序,在此做个分享吧.不喜勿喷 import requests import time from bs4 i ...

  10. 记一次 .NET 某医疗住院系统 崩溃分析

    一:背景 1. 讲故事 最近收到了两起程序崩溃的dump,查了下都是经典的 double free 造成的,蛮有意思,这里就抽一篇出来分享一下经验供后面的学习者避坑吧. 二:WinDbg 分析 1. ...