Mysql Nested-Loop Join Algorithms
MySQL在多表之间执行join时,利用一种nested-loop algorithm 或者其变种;(嵌套循环)
Nested-Loop Join Algorithm
一个简单的嵌套循环连接(NLJ)算法 从第一个表读取一行,然后传递给Join中的其他表依次读取,过程一直重复剩余的表都被Join。
假设在三个表t1,t2,t3做连接时:
Table Join Type t1 range t2 ref t3 ALL
如下:
for each row in t1 matching range { for each row in t2 matching reference key { for each row in t3 { if row satisfies join conditions, send to client } } }
因为嵌套循环连接每次传递一行到内表中,通常要在内表处理好多次。
Block Nested-Loop Join Algorithm(块嵌套循环连接算法)
Block Nested-loop(BNL)连接算法利用缓存外部循环读取的数据行来减少在内表中读取的次数。e.g.假如外表读取并缓存10行数据,缓存传递给以下个内表,内表可以在缓存中直接比较这10行数据,而不用再重新读取外表的10行数据,以数量级的方式减少内表读取次数。
MYSQL 用 join Buffer有一下几种条件:
1: join buffer size 系统变量决定了每个join buffer的大小。
2:join buffer可以用于all, index,range表访问类型。
3: 每个join分配一个buffer,所以一个查询可以用多个join buffer.
4: 如果第一个表为noconst table,则join buffer不会被分配,即使他的访问类型为all或者index.
5: Join buffer在执行是分配,查询完成后释放。
6: join Buffer只缓存感兴趣的(需要返回给client)的列,并不是一整行数据都缓存。
比较之前的NLJ算法(没有Buffer):
for each row in t1 matching range { for each row in t2 matching reference key { store used columns from t1, t2 in join buffer if buffer is full { for each row in t3 { for each t1, t2 combination in join buffer { if row satisfies join conditions, send to client } } empty buffer } } } if buffer is not empty { for each row in t3 { for each t1, t2 combination in join buffer { if row satisfies join conditions, send to client } } }
如果t1,t2保存在连接缓存的组合大小为S,组合个数为C,那么t3扫描次数是:
(S * C)/join_buffer_size + 1
t3的扫描次数会随着join_buffer_si增加而减少,当连接缓存增加到了可以包含所有记录,在大也不能减少扫描次数。