一 介绍
相信许多开发/DBA在使用MySQL的过程中,对于MySQL处理多表关联的方式或者说性能一直不太满意。对于开发提交的含有join的查询,一般比较抗拒,从而建议将join拆分,避免join可能带来的性能问题,同时也增加了程序和DB的网络交互。
5.5 版本之前,MySQL本身只支持一种表间关联方式,就是嵌套循环(Nested Loop)。如果关联表的数据量很大,则join关联的执行时间会非常长。在5.5以后的版本中,MySQL通过引入BNL算法来优化嵌套执行,本文介绍两种join算法 Nested-Loop Join (NLJ) 和Block Nested-Loop Join(BNL) .
二 原理
2.1 Nested Loop Join算法
NLJ 算法:将驱动表/外部表的结果集作为循环基础数据,然后循环从该结果集每次一条获取数据作为下一个表的过滤条件查询数据,然后合并结果。如果有多表join,则将前面的表的结果集作为循环数据,取到每行再到联接的下一个表中循环匹配,获取结果集返回给客户端。
Nested-Loop 的伪算法如下:
因为普通Nested-Loop一次只将一行传入内层循环, 所以外层循环(的结果集)有多少行, 内存循环便要执行多少次.在内部表的连接上有索引的情况下,其扫描成本为O(Rn),若没有索引,则扫描成本为O(Rn*Sn)。如果内部表S有很多记录,则SimpleNested-Loops Join会扫描内部表很多次,执行效率非常差。
2.2 Block Nested-Loop Join算法
BNL 算法:将外层循环的行/结果集存入join buffer, 内层循环的每一行与整个buffer中的记录做比较,从而减少内层循环的次数.
举例来说,外层循环的结果集是100行,使用NLJ 算法需要扫描内部表100次,如果使用BNL算法,先把对Outer Loop表(外部表)每次读取的10行记录放到join buffer,然后在InnerLoop表(内部表)中直接匹配这10行数据,内存循环就可以一次与这10行进行比较, 这样只需要比较10次,对内部表的扫描减少了9/10。所以BNL算法就能够显著减少内层循环表扫描的次数.
SET optimizer_switch='block_nested_loop=on';
前面描述的query, 如果使用join buffer, 那么实际join示意如下:
如果t1, t2参与join的列长度只和为s, c为二者组合数, 那么t3表被扫描的次数为
扫描t3的次数随着join_buffer_size的增大而减少, 直到join buffer能够容纳所有的t1, t2组合, 再增大join buffer size, query 的速度就不会再变快了.
2.3 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算法。
四 参考资料
5.6 版本BNL 支持outer join and semi-join ,并且和其他的特性比如BKA 相关联,后面会写文章整理其他的优化点。
《Nested-Loop Join Algorithms》
《Block Nested-Loop and Batched Key Access Joins》
《mysql的join buffer》
以上转载自 https://blog.csdn.net/u014756578/article/details/52795545
mysql的sort buffer和join buffer介绍
摘要:如果应用中,很少出现join语句,则可以不用太在乎join_buffer_size参数的设置大小。如果join语句不是很少的话,个人建议可以适当增大join_buffer_size到1MB左右,如果内存充足可以设置为2MB...
相关参数查看命令
SELECT @@join_buffer_size;
SELECT @@sort_buffer_size;
==========================================================================================
join_buffer_size
当我们的join是ALL,index,rang或者Index_merge的时候使用的buffer。
实际上这种join被称为FULL JOIN。
实际上参与join的每一个表都需要一个join buffer。
所以在join出现的时候,至少是2个。
join buffer的这只在mysql5.1.23版本之前最大为4G,但是从5.1.23版本开始,再出了windows之外的64为平台上可以超出4GB的限制。
系统默认是128KB。
==========================================================================================
sort_buffer_size
sort buffer是系统中对数据进行排序的时候用到的Buffer。
sort buffer同样是针对单个线程的,所以当多个线程同时进行排序的时候,系统中就会出现多个sort buffer。
我们一般可以通过增大sort buffer的大小来提高order by或者group by的处理性能。
系统默认大小时2MB,最大限制和join buffer一样。
==========================================================================================
优化建议
如果应用中,很少出现join语句,则可以不用太在乎join_buffer_size参数的设置大小。
如果join语句不是很少的话,个人建议可以适当增大join_buffer_size到1MB左右,如果内存充足可以设置为2MB。
对于sort_buffer_size来说,一般设置为2-4MB可以满足大多数应用的需求。
当然,如果应用中的排序都比较大。内存充足却并发量不是特别大的时候,也可以继续增大sort buffer size的设置。
最后需要注意的是,每一个线程都会创建自己独立的buffer而不是整个系统共享,所以设置的值过大会造成系统内存不足
以上转载自 https://blog.csdn.net/qq_21064841/article/details/53395899