MySQL中的Block Nested Loop优化分析

前言

一般在MySQL规范中,都会规定如果两张表进行join查询,那么join的字段一定要有索引,在之前的文章中我们分析了MySQL join大小表前后顺序影响分析,这是在有索引的情况下,今天我们再来看看如果没有索引MySQL会如何处理。

数据准备

新建了两张表,分别为t1,t2。

t1和t2表都是一个id字段作为主键,一个c字段,没有索引。
在这里插入图片描述

分别插入10条数据

t1,t2表数据都如下

在这里插入图片描述

Join查询

EXPLAIN select * from t1 LEFT JOIN t2 on t1.c = t2.c

通过执行分析可以看到出现了Using join buffer (Block Nested Loop)
在这里插入图片描述

Block Nested Loop分析

Block Nested Loop实际上MySQL的一种优化,正常情况下,在没有索引的情况下进行join关联查询,那执行流程应该如下:

1、先从t1查询一行数据。
2、然后到t2中进行匹配,需要匹配10次。
3、然后重复1~2步。

这样下来一共需要执行10*10=100次查找。

如果两张表数据都为1W条,那就是需要1亿次查找,这样的效率显然太差了。

那么Block Nested Loop的优化思路很简单,就是把一张表的数据先全部读到内存中,然后在内存中进行匹配,流程如下:

1、先把t1表的数据全部读取到内存中(join buffer)。
2、然后用t2表的每一行和join buffer中的数据进行匹配。

这样下来,虽然整体的查找次数并没有减少,但是整个匹配过程就在内存中完成的,速度会快很多。

join buffer满了怎么办

当然,你可能已经想到了如果join buffer一次放不下整张表的数据怎么办?

首先,我们要知道join buffer的大小是由join_buffer_size参数来控制的,如果一次放不下,那很简单,就分批次处理,每次放一部分到join buffer中,然后再去另一张表匹配,匹配完之后,清空join buffer,再处理下一批,现在,假设我们需要分两批才能处理完成,那么整个流程如下:

1、先把t1表前5条数据读到join buffer中。
2、然后用t2表去匹配join buffer中的前5条。
3、记录下匹配结果。
4、清空join buffer。
5、再把t1表后5条读取join buffer中。
6、然后用t2表去匹配join buffer中的后5条。
7、记录下匹配结果。

可以看出,整个过程需要两次t2表的全表扫描,主要原因就在于join buffer一次性放不下,也就是说,如果批次被拆分的越多,那对于整个性能来说,影响也就越大,所以这就是为什么当遇到join查询慢的时候,有些文章会建议你调大join_buffer_size试试。

大表驱动还是小表驱动

通过MySQL join大小表前后顺序影响分析 这篇文章,我们知道在有索引的情况下,应该让小表作为驱动表,那没有索引的情况下应该如何选择呢?

通过上面的流程分析可以看出,在join_buffer_size不变的情况下,影响最大的还是分批的数量,分批数量越大,需要全表扫描的次数就越多,因此我们应该让小表作为驱动表,这样就可以尽量减少分批的数量。

Guess you like

Origin blog.csdn.net/CSDN_WYL2016/article/details/120424148