浅析multi range read(MRR) & batch key access(BKA) & block nested loop(BNL)

另一篇文章介绍了index condition pushdown(ICP) 这篇讲叙的是MRR和与之相关的BKA

什么是MRR?

MRR:multi range read。不好解释,先来看个例子:

select * from tb where key_column = x

 

在没有MRR的情况下,它是这样得到结果的:

1.  select key_column, pk_column from tb where key_column=x order  by key_column ---> 假设这个结果集是t

2.  for each row in t ;   select non_key_column from tb where pk_column = pk_column_value。(在oracle里第2步叫回表?)

在有MRR的情况下,它是这样执行的:

1.  select key_column, pk_column from tb where key_column = x  order by key_column ---> 假设这个结果集是t

2.  将结果集t放在buffer里面(直到buffer满了),然后对结果集t按照pk_column排序      ---> 假设排序好的结果集是t_sort

3.  select non_key_column fromtb where pk_column in (select pk_column from t_sort)

 

两者的区别主要是两点

1. 没有MRR的情况下,随机IO增加,因为从二级索引里面得到的索引元组是有序,但是他们在主键索引里面却是无序的,所以每次去主键索引里面得到non_key_column的时候

都是随机IO。(如果索引覆盖,那也就没必要利用MRR的特性了,直接从索引里面得到所有数据)

2. 没有MRR的情况下,访问主键索引的次数也会增加。没有MRR的情况下,二级索引里面得到多少行,那么就要去访问多少次主键索引(也不能完全这样说,因为mysql实现了BNL),而有了MRR的时候,次数就大约减少为之前次数t/buffer_size。

 所以说MRR主要解决的就是这两个问题。


那么看看使用了MRR的explain:

mysql> explain select c from test1 wherek in(25054, 24781, 23054, 25207, 25020);

+----+-------------+-------+-------+---------------+------+---------+------+------+------------------------+

| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra                 

+----+-------------+-------+-------+---------------+------+---------+------+------+------------------------+

|  1| SIMPLE      | test1 | range | k             | k    | 4      | NULL |  329 | Using where; Using MRR |

+----+-------------+-------+-------+---------------+------+---------+------+------+------------------------+

 

没有使用MRR的explain:

mysql> explain select c from test1 wherek in(25054, 24781, 23054, 25207, 25020);

+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+

| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra      

+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+

|  1| SIMPLE      | test1 | range | k             | k   | 4       | NULL |  124 | Using where |

+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+

 

那么提到了MRR,还有一个概念BKA(batch key access) 就不得不提了。

BKA就是为解决上面所说的:在没有MRR的情况下,被join表访问的次数大多(实际上上面的例子中可以把主键索引看成一个被join的表)。BKA就是每次批量的提交一批行给被join的表。实际上在BKA实现的过程中就是通过传递一个参数给MRR接口,本质上还是在MRR里面实现,下面这幅图则展示了他们之间的关系。

NBL和BKA都是批量的提交一部分行给被join的表,从而减少访问的次数,那么它们有什么区别呢?NBL和BKA的思想是类似的,详情见:

http://www.mysqlab.net/docs/refman/en-5.1/page/nested-loop-joins.html。

而BKA(batch key access)主要是指在被join表上有索引可以利用,那么就在行提交给被join的表之前,对这些行按照索引字段进行排序,因此减少了随机IO,排序这才是两者最大的区别


你可能还会问,为什么有了BKA还要NBL?

第一、NBL比BKA出现的早,BKA直到5.6才出现,而NBL至少在5.1里面就存在

第二、BKA是针对被join的表上面有index可以使用(也就是有key),但是如果用户没有在上面建index呢?那么就用NBL了咯

 

总结:

MRR主要是对于减少join中的随机IO和被join的表的访问次数,没有MRR之前mysql中最好的join算法都是NBL,虽然可以减少被join表的次数,但是随机IO这个还是解决不了,而现在两个问题都解决了。而性能对比测试则由于现在mysql 5.6还只是开发版本所以没测,以后可以试试。

 

参考资料:

1. http://www.mysqlab.net/docs/refman/en-5.1/page/nested-loop-joins.html

2. http://www.mysqlperformanceblog.com/2012/04/04/join-optimizations-in-mysql-5-6-and-mariadb-5-5/

3. http://www.mysqlperformanceblog.com/2012/03/21/multi-range-read-mrr-in-mysql-5-6-and-mariadb-5-5/

4. http://kb.askmonty.org/en/multi-range-read-optimization#case-3-key-sorting-for-batched-key-access

你可能感兴趣的:(JOIN,mysql,IO,buffer,Access,nested)