MySQL中的Join 的算法(NLJ、BNL、BKA)

这篇具有很好参考价值的文章主要介绍了MySQL中的Join 的算法(NLJ、BNL、BKA)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

微信公众号:Java随想录

目录
  • 摘要
  • 什么是Join
  • Index Nested-Loop Join
  • Block Nested-Loop Join
  • MRR & BKA
  • 总结

摘要

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算法。对于不好在索引的情况,可以基于临时表的改进方案,提前过滤出小数据添加索引。


本篇文章就到这里,感谢阅读,如果本篇博客有任何错误和建议,欢迎给我留言指正。文章持续更新,可以关注公众号第一时间阅读。
文章来源地址https://www.toymoban.com/news/detail-436309.html

到了这里,关于MySQL中的Join 的算法(NLJ、BNL、BKA)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SQL中的——左连接(Left join)、右连接(Right join)、内连接(Inner join)

    最近有一个开发需求,需要实现一个复杂年度报表,前后端都是博主开发,这里的业务逻辑比较复杂,也很锻炼sql能力,这里博主也将表的内外连接做了一个整理分享给大家 首先还是介绍一下这三个的定义 1.Left join:即 左连接 ,是以左表为基础,根据ON后给出的两表的条件

    2024年02月12日
    浏览(47)
  • MySQL left join 和 left outer join 区别

    先说结论: left join 和 left outer join 的结果是一致的。 我不知道各位大神是怎么测试的,网上面就说两个不一样,我A、B表都是有重复数据的,为啥结果是一样的。 表A 表B 左连接 左外连接 以下MySQL官方文档的说明(2664页),outer join是为了某些第三方程序的兼容性而存在的。 微软

    2024年02月10日
    浏览(42)
  • js中的join()方法

    join()方法就是将array数据中每个元素都转为字符串,用自定义的连接符分割 1、join(\\\'\\\')将数组元素 无缝拼接 输出结果:apple 2、join(\\\' \\\') 将数组元素 以空格分割 输出结果:Apple is on my table 3、join()将数组 每个元素都转为字符串 ,用法等同于toString()  4、 join()将数组转换为页面元素

    2024年02月16日
    浏览(22)
  • MySQL多表查询内连接外连接详解,join、left join、right join、full join的使用

    目录 1、多表查询概览 1.1、分类 1.2、外连接的分类 1.3、常用的SQL语法标准 2、内外联接案例 2.1、初始化表 2.2、内连接 2.3、外连接案例 2.4、全连接案例 2.5、union和union all 2.6、实现MySQL全连接 2.7、内外连接面试基础 2.8、SQL99多表查询新特性 1.1、分类 可以根据3个角度进行分类

    2024年02月05日
    浏览(65)
  • MySQL - Left Join和Inner Join的效率对比,以及优化

    最近在写代码的时候,遇到了需要多表连接的一个问题,初始sql类似于: 这样的多个left join组合,总觉得这种写法是有问题的,后续使用inner join发现速度要比left join快一些 关于left join的概念,大家是都知道的(返回左边全部记录,右表不满足匹配条件的记录对应行返回nul

    2024年02月03日
    浏览(52)
  • Mysql表关联简单介绍(inner join、left join、right join、full join不支持、笛卡尔积)

    A 是1、2、3 B是2、3、4 A、B的交集是A∩B = 2、3 A、B的并集是 AUB = 1、2、3、4 A、B的差集是 A-B = 1 B、A的差集是 B-A = 4 造数据 select A. ,B. from xin_stu_t_bak A inner join xin_teach_t_bak B on A.relation_id = B.id order by A.id; select distinct A. ,B. from xin_stu_t_bak A inner join xin_teach_t_bak B on A.relation_id = B.id

    2024年01月17日
    浏览(53)
  • MySQL Join 类型

    SQL Join 类型的区别 Inner Join: 左,右表都有的数据 Left Join: 左表返回所有的行, 右表没有的补充为 NULL Right Loin: 右表返回所有的行, 左表没有的补充为 NULL Full Outer Join: 左表 + 右表 所有数据 用户表: 答题表: 查询左表 和 右表都有的数据 用户表 user_no = 1000 和 答题表 user_no = 6543 ,

    2024年02月08日
    浏览(31)
  • clickhouse join查询算法

    算法对比: 使用方法: 每个算法试试测试一下性能,如果没效果,考虑一下宽表。

    2024年01月16日
    浏览(70)
  • ClickHouse的Join算法

    ClickHouse是一款开源的列式分析型数据库(OLAP),专为需要超低延迟分析查询大量数据的场景而生。为了实现分析应用可能达到的最佳性能,分析型数据库(OLAP)通常将表组合在一起形成一个大宽表,这个过程称为数据反规范化(data denormalization)。大宽表通过避免JOIN连接来

    2024年02月09日
    浏览(34)
  • Mysql Join 多条件的小坑

    一般情况我们可能只在join on 后面添加唯一的关联条件,但是如果在on后面添加多个条件会发生什么呢? 对于inner join 表现与在where后面添加条件一致 但是对于left join,情况就比较微妙了。 对于左表添加条件,没有任何效果。表a的其他id数据仍然查询出来了 对于右表添加条件

    2024年02月07日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包