Using join buffer (Block Nested Loop)java
msyql的表链接算法算法
NLJ 算法:将驱动表/外部表的结果集做为循环基础数据,而后循环从该结果集每次一条获取数据做为下一个表的过滤条件查询数据,而后合并结果。若是有多表join,则将前面的表的结果集做为循环数据,取到每行再到联接的下一个表中循环匹配,获取结果集返回给客户端。oop
Nested-Loop 的伪算法以下:优化
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 } } }
Because the NLJ algorithm passes rows one at a time from outer loops to inner loops, tables processed in the inner loops typically are read many timesspa
由于普通Nested-Loop一次只将一行传入内层循环, 因此外层循环(的结果集)有多少行, 内存循环便要执行多少次.在内部表的链接上有索引的状况下,其扫描成本为O(Rn),若没有索引,则扫描成本为O(Rn*Sn)。若是内部表S有不少记录,则SimpleNested-Loops Join会扫描内部表不少次,执行效率很是差。code
BNL 算法:将外层循环的行/结果集存入join buffer, 内层循环的每一行与整个buffer中的记录作比较,从而减小内层循环的次数。索引
举例来讲,外层循环的结果集是100行,使用NLJ 算法须要扫描内部表100次,若是使用BNL算法,先把对Outer Loop表(外部表)每次读取的10行记录放到join buffer,而后在InnerLoop表(内部表)中直接匹配这10行数据,内存循环就能够一次与这10行进行比较, 这样只须要比较10次,对内部表的扫描减小了9/10。因此BNL算法就可以显著减小内层循环表扫描的次数。内存
前面描述的query, 若是使用join buffer, 那么实际join示意以下:it
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参与join的列长度只和为s, c为两者组合数, 那么t3表被扫描的次数为 io
(S * C)/join_buffer_size + 1
扫描t3的次数随着join_buffer_size的增大而减小, 直到join buffer可以容纳全部的t1, t2组合, 再增大join buffer size, query 的速度就不会再变快了。
MySQL使用Join Buffer有如下要点:
1. join_buffer_size变量决定buffer大小。
2. 只有在join类型为all, index, range的时候才可使用join buffer。
3. 可以被buffer的每个join都会分配一个buffer, 也就是说一个query最终可能会使用多个join buffer。
4. 第一个nonconst table不会分配join buffer, 即使其扫描类型是all或者index。
5. 在join以前就会分配join buffer, 在query执行完毕即释放。
6. join buffer中只会保存参与join的列, 并不是整个数据行。
如何使用
5.6版本及之后,优化器管理参数optimizer_switch中中的block_nested_loop参数控制着BNL是否被用于优化器。默认条件下是开启,若果设置为off,优化器在选择 join方式的时候会选择NLJ算法。
==========END==========