MySQL的Join原理

Join原理

mysql的join算法叫做Nested-Loop Join(嵌套循环连接)

而这个Nested-Loop Join有三种变种,下面分别介绍下

Simple Nested-Loop

这个算法相当简单、直接。即驱动表中的每一条记录与被驱动表中的记录进行比较判断(就是个笛卡尔积)。对于两表联接来说,驱动表只会被访问一遍,但被驱动表却要被访问到好多遍

假设R为驱动表,S被驱动表,用伪代码表示一下这个过程就是这样:

for r in R                      # 扫描R表(驱动表)
    for s in S                   # 扫描S表(被驱动表)
        if (r and s satisfy the join condition)  # 如果r和s满足join条件
            output result    # 返回结果集

所以如果R有1万条数据,S有1万条数据,那么数据比较的次数1万 * 1万 =1亿次,这种查询效率会非常慢。

Index Nested-Loop

这个是基于索引进行连接的算法

它要求被驱动表上有索引,可以通过索引来加速查询。

假设R为驱动表,S被驱动表,用伪代码表示一下这个过程就是这样:

For r in R                  # 扫描R表
    for s in Sindex                    # 查询S表的索引(固定3~4次IO,B+树高度)
        if (s == r)                   # 如果r匹配了索引s
            output result   # 返回结果集

Block Nested-Loop

这个算法较Simple Nested-Loop Join的改进就在于可以减少被驱动表的扫描次数

因为它使用Join Buffer来减少内部循环读取表的次数

假设R为驱动表,S被驱动表,用伪代码表示一下这个过程就是这样:

for r in R                             # 扫描表R
    store p from R in Join Buffer    # 将部分或者全部R的记录保存到Join Buffer中,记为p
    for s in S                        # 扫描表S
        if (p and s satisfy the join condition)        # p与s满足join条件
           output result                    # 返回为结果集

可以看到相比Simple Nested-Loop Join算法,Block Nested-LoopJoin算法仅多了一个所谓的Join Buffer

为什么这样就能减少被驱动表的扫描次数呢?

下图相比更好地解释了Block Nested-Loop Join算法的运行过程

图片

可以看到Join Buffer用以缓存联接需要的列(所以再次提醒我们,最好不要把*作为查询列表,只需要把我们关心的列放到查询列表就好了,这样还可以在join buffer中放置更多的记录呢,是不是这个道理哈,哈哈)

然后以Join Buffer批量的形式和被驱动表中的数据进行联接比较。

关于Join Buffer

  1. Join Buffer会缓存所有参与查询的列而不是只有Join的列。
  2. join_buffer_size的默认值是256K

总结

在选择Join算法时,会有优先级:

Index Nested-LoopJoin > Block Nested-Loop Join > Simple Nested-Loop Join

当不使用Index Nested-Loop Join的时候,默认使用Block Nested-Loop Join

使用Block Nested-Loop Join算法需要开启优化器管理配置的optimizer_switch的设置block_nested_loop为on,默认为开启。

Join优化

通过上面的简单介绍,可以总结出以下几种优化思路

1.用小结果集驱动大结果集,减少外层循环的数据量

2.如果小结果集和大结果集连接的列都是索引列,mysql在join时也会选择用小结果集驱动大结果集,因为索引查询的成本是比较固定的,这时候外层的循环越少,join的速度便越快。

3.为匹配的条件增加索引:争取使用Index Nested-Loop Join,减少内层表的循环次数

4.增大join buffer size的大小:当使用Block Nested-Loop Join时,一次缓存的数据越多,那么外层表循环的次数就越少,减少不必要的字段查询:

5.当用到Block Nested-Loop Join时,字段越少,join buffer 所缓存的数据就越多,外层表的循环次数就越少;

猜你喜欢

转载自blog.csdn.net/qq_53267860/article/details/125024417