当初有两张表,t1表100行,t2表1000行select * from t1 straight_join t2 on (t1.a=t2.b);

Simple Nested-Loop Join(没有被MYSQL应用)

前提:join字段t2.b不存在索引
查问过程:全表扫描t1,而后将每一条记录a字段作为条件到被驱动表t2进行一次全表扫描,也就是100次全表扫描。

Block Nested-Loop Join(简称BNL)

前提:join字段t2.b不存在索引。
查问过程:全表扫描t1,将数据放入join buffer,再将被驱动表t2数据与join buffr里的t1数据进行批量比照。当t1表数据过多,join buffer存不下时,会将数据分段反复执行整个查问过程。
tips:所以某些场景下能够通过设置join_buffer_size增大join buffer进步join速度。
通过explain的Extra 字段有 Using join buffer(Block Nested Loop)。

Index Nested-Loop Join(简称NLJ)

前提:join字段t2.b存在索引。
查问过程:全表扫描t1,循环100次(将第一条记录a字段作为条件去被驱动表t2查问二级索引树,失去主键ID,再回表查问主键索引树)。
应用BKA优化查问过程:全表扫描t1,循环100次(将每一条记录a字段放入join buffer),将join buffer里的a字段作为条件去被驱动表t2范畴查问二级索引树,失去主键ID,将主键ID放入read_rnd_buffer,递增排序后,范畴查问主键索引树。
工夫复杂度:100+1002log2^1000(先扫描驱动表100行,再循环100次扫描二级索引树失去主键ID,再"回表"扫描主键索引树1002log2^1000)。
tips:假如驱动表的行数是 N,被驱动表行数M,也就是N+N2log2^M。能够看出驱动表的行数N对后果影响更大,所以才有了小表驱动大表。

Multi-Range Read(针对回表的优化)

因为大多数的数据都是依照主键递增程序插入失去的,所以咱们能够认为,如果依照主键的递增程序查问的话,对磁盘的读比拟靠近程序读,可能晋升读性能。

开启MRR优化set optimizer_switch="mrr=on"稳固应用MRR优化,依照官网文档的说法,是当初的优化器策略,判断耗费的时候,会更偏向于不应用 MRR,把 mrr_cost_based 设置为 off,就是稳固应用 MRR 了set optimizer_switch="mrr=on,mrr_cost_based=off"

所以回表会变为:依据二级索引树失去主键ID后存入read_rnd_buffer(read_rnd_buffer_size参数管制),进行递增排序,拿排序后的主键ID去主键索引树进行范畴查问。(用上MRR,通过explain的Extra 字段有 Using MRR)

Batched Key Access(针对NLJ的优化,BKA依赖MRR)

开启BKA优化,前两个参数是为了开启MRRset optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

join_buffer 在 BNL 算法里的作用,是暂存驱动表的数据。然而在 NLJ 算法里并没有用。那么,刚好就能够复用 join_buffer 到 BKA 算法中。
在NLJ过程中,因为从驱动表 t1,一行行地取出 a 的值,再到被驱动表 t2 去做 join。也就是说,对于表 t2 来说,每次都是匹配一个值。这时,MRR 的劣势就用不上了。所以能够将t1表的a字段放入join buffer,递增排序后,在t2的b字段索引树上进行范畴查问,失去主键ID,再利用MRR优化进行后续回表。

hash join

因为join_buffer 外面保护的是一个无序数组,所以在和被驱动表join时就须要逐条匹配,如果通过hash构造去存储驱动表数据的话,就能大大减少等值判断次数。

存在where条件(小表驱动大表)

假如t1中100条c=100的数据select * from t2 straight_join t1 on (t2.b=t1.a) where t2.id <= 10 and t1.c = 100;

这个时候须要抉择t2作为驱动表,因为先依据where条件过滤后失去10行的后果集作为驱动表,再进行join,join的过程再对t1.c=100的条件过滤。