Nested-Loop Join Algorithms

MySQL使用嵌套循环算法来实现多表之间的联接。

Nested-Loop Join Algorithms

一个简单的嵌套循环联接(NLJ)算法,循环从第一个表中依次读取行,取到每行再到联接的下一个表中循环匹配。这个过程会重复多次直到剩余的表都被联接了。 假设表t1、t2、t3用下面的联接类型进行联接:

Table   Join Type
t1      range
t2      ref
t3      ALL

如果使用的是简单NLJ算法,那么联接的过程像这样:

for each row in t1 matching range {
  for each row in t2 matching reference key {
    for each row in t3 {
      if row satisfies join conditions,
          send to client
    }
  }
}

因为NLJ算法是通过外循环的行去匹配内循环的行,所以内循环的表会被扫描多次。

Block Nested-Loop Join Algorithm

一个块嵌套循环联接(BNL)算法,将外循环的行缓存起来,读取缓存中的行,减少内循环的表被扫描的次数。例如,如果10行读入缓冲区并且缓冲区传递给下一个内循环,在内循环读到的每行可以和缓冲区的10行做比较。这样使内循环表被扫描的次数减少了一个数量级。 MySQL使用联接缓冲区时,会遵循下面这些原则:

  • join_buffer_size系统变量的值决定了每个联接缓冲区的大小。
  • 联接类型为ALL、index、range时(换句话说,联接的过程会扫描索引或数据时),MySQL会使用联接缓冲区。
  • 缓冲区是分配给每一个能被缓冲的联接,所以一个查询可能会使用多个联接缓冲区。
  • 联接缓冲区永远不会分配给第一个表,即使该表的查询类型为ALL或index。
  • 联接缓冲区联接之前分配,查询完成之后释放。
  • 使用到的列才会放到联接缓冲区中,并不是所有的列。

上面的例子使用的是NLJ算法(没有使用缓存),使用缓存的联接方式像下面这样:

for each row in t1 matching range {
  for each row in t2 matching reference key {
    store used columns from t1, t2 in join buffer
    if buffer is full {
      for each row in t3 {
        for each t1, t2 combination in join buffer {
          if row satisfies join conditions,
          send to client
        }
      }
      empty buffer
    }
  }
}

if buffer is not empty {
  for each row in t3 {
    for each t1, t2 combination in join buffer {
      if row satisfies join conditions,
      send to client
    }
  }
}

对上面的过程解释如下: 1. 将t1、t2的联接结果放到缓冲区,直到缓冲区满为止; 2. 遍历t3,内部再循环缓冲区,并找到匹配的行,发送到客户端; 3. 清空缓冲区; 4. 重复上面步骤,直至缓冲区不满; 5. 处理缓冲区中剩余的数据,重复步骤2。

设S是每次存储t1、t2组合的大小,C是组合的数量,则t3被扫描的次数为:

(S * C)/join_buffer_size + 1

由此可见,随着join_buffer_size的增大,t3被扫描的次数会较少,如果join_buffer_size足够大,大到可以容纳所有t1和t2联接产生的数据,t3只会被扫描1次。

英文地址:http://dev.mysql.com/doc/refman/5.5/en/nested-loop-joins.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码农阿宇

C# 6.0中你不知道的新特性

为什么写? 今天去上班的公交上,有朋友在张队(张善友)的微信群里,发了一个介绍C# 6.0新特性的视频,视频7分钟,加上本人英语实在太low,整体看下来是一脸懵...

2354
来自专栏Java学习网

困扰开发人员的八大代码异常问题

代码异常对于每个开发人员时时刻刻要面对的问题,兴奋的写完一段代码,信心满满的运行一下,结果一个异常给你当头 一棒,你还得意吗?异常处理的好不好,考验着每个开发人...

2564
来自专栏快乐八哥

Javascript中数组的使用

Array在Javascript程序开发中是一个经常使用到。一个数组可以存储Javascript支持的任何数据类型。 1.基本知识点 //创建一个对象并初始化它...

1639
来自专栏Coding01

链式编程

链式编程或者链式写法,是将多个方法 (函数) 通过点号 (.) 或者 (->)等符号链接在一起成为一句代码,这样不仅可以增强代码的可读性,而且每次链接,都是对对...

693
来自专栏King_3的技术专栏

leetcode-201-数字范围按位与

给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。

772
来自专栏技术博客

C#函数方法集

1、DateTime 数字型 System.DateTime currentTime=new System.DateTime();

882
来自专栏小工匠技术圈

【小工匠聊密码学】--base58编码

1594
来自专栏编程心路

看完这个,Java IO从此不在难

Java IO 体系看起来类很多,感觉很复杂,但其实是 IO 涉及的因素太多了。在设计 IO 相关的类时,编写者也不是从同一个方面考虑的,所以会给人一种很乱的感...

1085
来自专栏大内老A

通过实例模拟ASP.NET MVC的Model绑定机制:简单类型+复杂类型

总的来说,针对目标Action方法参数的Model绑定完全由组件ModelBinder来实现,在默认情况下使用的ModelBinder类型为DefaultMod...

2218
来自专栏我是攻城师

ElasticSearch+Solr几个case笔记

2834

扫码关注云+社区