上面介绍了两种算法,分别是Index Nested-Loop Join和Block Nested-Loop Join

但是这并不是MySQL想要提供给用户的最终抉择

首先是两张表t1 t2来进行展开

create table t1(id int primary key, a int, b int, index(a));

create table t2 like t1;

drop procedure idata;

delimiter ;;

create procedure idata()

begin

declare i int;

set i=1;

while(i<=1000)do

insert into t1 values(i, 1001-i, i);

set i=i+1;

end while;

set i=1;

while(i<=1000000)do

insert into t2 values(i, i, i);

set i=i+1;

end while;

end;;

delimiter ;

call idata();

在表t1中 id和a是相反的

在t2中,有100万条数据

有了一个新的优化 Multi-Range Read的优化

这个优化的核心在于

首先说,InnoDB采用了B+树的结构类型

也就是说,在InnoDB中

我们在一个普通索引上查到了主键id的值,然后回到主键索引上查询整行的数据

然后有这个回表的操作是一行行的查询,

效率必然不如批量的查数据

假设,我们执行了select * from t1 where a>=1 and a<=100;

图片

如果按照a的顺序去查询索引表,那么即为可能是无序的主键id

但是大部分的数据都是按照主键自增的顺序插入得到的,所以按照主键id来顺序查找的话,就是有序的,可能用顺序读来提升性能

MRR的优化思路就这样

1,根据索引a,一次性的查询出所有满足条件的顺序,将id放入read_rnd_buffer的

2.然后进行id递增排序

3.然后将排序后的id数组,去主键索引id中查询记录

这里read_rnd_buffer的大小是由read_rnd_buffer_size参数控制的,在步骤1里面,,如果已经放满了,就会先执行,2 3

然后清空read_rnd_buffer

如果想要稳定的使用MRR优化,还需要开启set optimizer_switch=”mrr_cost_based=off”

让其持久开启

图片

图片

上面说明使用了MRR优化

也就是说MRR能够提升性能的关键,就是查询一定范围的值,然后排序,需要有足够的数量,才能进行体现顺序性的优势

上述说的MRR更加适合于无索引的优化

我们还引入了Batched Key Access

BKA算法对NLJ算法的优化

图片

因为原本的NJL算法,是从驱动表中,一行行的取出a的值,然后利用索引,到表t2做join

那么可以一次性的多传一些值给被驱动表

先把驱动表数据取出来一部分,然后放在一个临时内存中,就是join_buffer中

在NLJ中,因为使用了索引,所以join_buffer在其中没有使用,BKA正好使用这个临时空挡

图片

在join_buffer中,放入的数据是P1-P100,表示的是会去查询需要的字段,但是join_buffer放不下的话,就会拆分成多次来执行

开启BKA需要设置,

set optimizer_switch=’mrr=on,mrr_cost_based=off,batched_key_access=on’;

对于BNL的优化

因为BNL中,可能存在对一个冷表多次查询的情况

多次扫描被驱动表,占用了磁盘IO

判断join条件,需要进行M*N此对比

导致Buffer Pool的数据被污染了

这样,如果发现非要使用BNL算法,也最好先给被驱动表加上索引,转为BKA算法

假如没法使用BKA算法的

可以考虑其他的数据库使用的一种优化方式,在MySQL中可能暂时不支持

就是hash join

如果join buffer中维护的不是一个无序的数组,而是一个hash表的话,那么执行语句就快了吧

但是Mysql没有提供

如果这种优化的思路执行的话

1.select * from t1.取得t1的所有数据,在join buffer中存入一个hash结构

2.然后查询被驱动表中的所有满足数据,获取所有满足条件的数据

3.拿着着2000行数据,到业务端进行hash匹配,符合匹配的,拿其的字段来匹配,最后加入结果集

理论上,这个过程会很快

这章总结下来说,

BNL算法效率低,可以通过加索引编程BKA优化

BKA优化是MySQL默认支持的,可以直接使用

假如有如下的一个语句,如何创建索引

select * from t1 join t2 on(t1.a=t2.a) join t3 on (t2.b=t3.b) where t1.c>=X and t2.c>=Y and t3.c>=Z;

首先

尽可能的缩减过滤条件,选择三个表上的c字段建立索引

那么选定了驱动表,就需要在被驱动表上建立索引

如果是t1 t2 t3这样的顺序,就是t2的a和t3的b上建立索引

如果是t3 t2 t1这样的顺序,就是t2的b和t1的a上建立索引

如果是t2是驱动表的话,就需要额外评估另外两个条件的过滤情况

发表评论

邮箱地址不会被公开。 必填项已用*标注