到底可不可以使用join

到底可不可以使用join

在实际生产中,关于join语句使用的问题,一般会集中在以下两类:

  1. 我们DBA不让使用join,使用join有什么问题呢?

  2. 如果有两个大小不同的表做join,应该用哪个表做驱动表呢?

以下创建两个表t1和t2来和你说明。

CREATE TABLE t2 (​ id int(11) NOT NULL, ​ a int(11) DEFAULT NULL, ​ b int(11) DEFAULT NULL, ​ PRIMARY KEY (id), ​ KEY a (a)) ENGINE=InnoDB;`

drop procedure idata;
delimiter ;;
create procedure idata()
begin
​ declare i int;
​ set i=1;
​ while(i<=1000)do
​ insert into t2 values(i, i, i);
​ set i=i+1;
​ end while;
end;;
delimiter ;
call idata();

create table t1 like t2;
insert into t1 (select * from t2 where id<=100)

Index Nested-Loop Join

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

如果直接使用join语句,MySQL优化器可能会选择表t1或t2作为驱动表,这里使用straight_join,让MySQL使用固定的连接方式执行查询。

若使用t1作为驱动表,这个语句的执行流程是这样的:

  1. 从表t1中读入一行数据 R;

  2. 从数据行R中,取出a字段到表t2里去查找;

  3. 取出表t2中满足条件的行,跟R组成一行,作为结果集的一部分;

  4. 重复执行步骤1到3,直到表t1的末尾循环结束。

我们称之为“Index Nested-Loop Join”,简称NLJ。

它对应的流程图如下所示:

img

一句话就是:从(驱动表)存储引擎层一行一行的获取数据,将满足条件的数据,根据条件(on)与被驱动表进行匹配,行成每一行数据。

值得注意的是:

在这里驱动表用户的全表扫描,被驱动表是树搜索过程(索引的原因)

Simple Nested-Loop Join

Index Nested-Loop Join中连接被驱动表时,使用的是树搜索,如果被驱动表用不上索引是怎么样的?

现在,我们把SQL语句改成这样:

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

这时候的流程跟Index Nested-Loop Join中的流程差不多,但是对被驱动表的匹配时变了!

Index Nested-Loop Join匹配被驱动表示,利用树搜索一一匹配,

而现在是对被驱动表进行全局扫描进行匹配。

我们称这个为Simple Nested-Loop Join算法。

当然,MySQL也没有使用这个Simple Nested-Loop Join算法,而是使用了另一个叫作“Block Nested-Loop Join”的算法,简称BNL。

Block Nested-Loop Join

当被驱动表中没有索引时,mysql中的BNL算法过程是这样的:

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

这个过程的流程图如下:

img

相比较Index Nested-Loop Join来讲,两者的时间复杂度一样,但是BNL是将驱动表数据读取在内存中,再进行匹配得,速度更快(Index Nested-Loop Join是从磁盘中读取数据再内存中进行匹配)

总结

一、开头两个问题的解决:

第一个问题:能不能使用join语句?

  1. 如果可以使用Index Nested-Loop Join算法,也就是说可以用上被驱动表上的索引,其实是没问题的;
  2. 如果使用Block Nested-Loop Join算法,扫描行数就会过多。尤其是在大表上的join操作,这样可能要扫描被驱动表很多次,会占用大量的系统资源。所以这种join尽量不要用。

所以你在判断要不要使用join语句时,就是看explain结果里面,Extra字段里面有没有出现“Block Nested Loop”字样。

第二个问题是:如果要使用join,应该选择大表做驱动表还是选择小表做驱动表?

  1. 总是应该使用小表做驱动表。

二、3个算法的理解

Index Nested-Loop Join: 驱动表全局扫描,被驱动表树搜索

Simple Nested-Loop Join:驱动表和被驱动表都是全局扫描

Block Nested-Loop Join: 方便比较,将驱动表数据放内存中(不用来回读取磁盘)

猜你喜欢

转载自blog.csdn.net/The_dream1/article/details/112471538