本文转载自Mysql的join算法

导语

在Mysql中,使用Nested-Loop Join的算法思想去优化joinNested-Loop Join翻译成中文则是“嵌套循环连接”。

举个例子:

select * from t1 inner join t2 on t1.id=t2.tid

  • t1称为外层表,也可称为驱动表。
  • t2称为内层表,也可称为被驱动表。
//伪代码表示:
List<Row> result = new ArrayList<>();
for(Row r1 in List<Row> t1){
for(Row r2 in List<Row> t2){
if(r1.id = r2.tid){
result.add(r1.join(r2));
}
}
}

在Mysql的实现中,Nested-Loop Join有3种实现的算法:

  • Simple Nested-Loop JoinSNLJ,简单嵌套循环连接
  • Index Nested-Loop JoinINLJ,索引嵌套循环连接
  • Block Nested-Loop JoinBNLJ,缓存块嵌套循环连接

    在选择Join算法时,会有优先级,理论上会优先判断能否使用INLJBNLJ

    Index Nested-LoopJoin > Block Nested-Loop Join > Simple Nested-Loop Join

Simple Nested-Loop

简单嵌套循环连接实际上就是简单粗暴的嵌套循环,如果table1有1万条数据,table2有1万条数据,那么数据比较的次数=1万 * 1万 =1亿次,这种查询效率会非常慢。

所以Mysql继续优化,然后衍生出Index Nested-LoopJoinBlock Nested-Loop Join两种NLJ算法。在执行join查询时mysql会根据情况选择两种之一进行join查询。

Index Nested-LoopJoin(减少内层表数据的匹配次数)

索引嵌套循环连接是基于索引进行连接的算法,索引是基于内层表的,通过外层表匹配条件直接与内层表索引进行匹配,避免和内层表的每条记录进行比较, 从而利用索引的查询减少了对内层表的匹配次数,优势极大的提升了 join的性能:

原来的匹配次数 = 外层表行数 * 内层表行数

优化后的匹配次数= 外层表的行数 * 内层表索引的高度

使用场景:只有内层表join的列有索引时,才能用到Index Nested-LoopJoin进行连接。

由于用到索引,如果索引是辅助索引而且返回的数据还包括内层表的其他数据,则会回内层表查询数据,多了一些IO操作。

Block Nested-Loop Join(减少内层表数据的循环次数)

缓存块嵌套循环连接通过一次性缓存多条数据,把参与查询的列缓存到Join Buffer 里,然后拿join buffer里的数据批量与内层表的数据进行匹配,从而减少了内层循环的次数(遍历一次内层表就可以批量匹配一次Join Buffer里面的外层表数据)。

当不使用Index Nested-Loop Join的时候,默认使用Block Nested-Loop Join

什么是Join Buffer

  • Join Buffer会缓存所有参与查询的列而不是只有Join的列。
  • 可以通过调整join_buffer_size缓存大小
  • join_buffer_size的默认值是256K,join_buffer_size的最大值在MySQL 5.1.22版本前是4G,而之后的版本才能在64位操作系统下申请大于4GJoin Buffer空间。
  • 使用Block Nested-Loop Join算法需要开启优化器管理配置的optimizer_switch的设置block_nested_loopon,默认为开启。

如何优化Join速度

  1. 用小结果集驱动大结果集,减少外层循环的数据量:
  2. 如果小结果集和大结果集连接的列都是索引列,mysql在内连接时也会选择用小结果集驱动大结果集,因为索引查询的成本是比较固定的,这时候外层的循环越少,join的速度便越快。
  3. 为匹配的条件增加索引:争取使用INLJ,减少内层表的循环次数
  4. 增大join buffer size的大小:当使用BNLJ时,一次缓存的数据越多,那么外层表循环的次数就越少
  5. 减少不必要的字段查询:
    • 当用到BNLJ时,字段越少,join buffer 所缓存的数据就越多,外层表的循环次数就越少;
    • 当用到INLJ时,如果可以不回表查询,即利用到覆盖索引,则可能可以提示速度。(未经验证,只是一个推论)

参考文档

https://www.wengbi.com/thread_99558_1.html

https://www.cnblogs.com/starhu/p/6418842.html

https://www.cnblogs.com/starhu/p/6418833.html

最新文章

  1. js无刷新上传文件
  2. Python全栈开发day8
  3. centos忘记root密码,重新设置的方法
  4. 交换两个数-c++实现
  5. 20160129.CCPP体系详解(0008天)
  6. HTML5 自适应rem布局
  7. -_-#【Better JS Code】严格模式
  8. 1:环境安装与介绍:canopy
  9. 快速理解Parquet的DL和RL
  10. elasticsearch基本操作之--java基本操作 api
  11. Chapter 5 Blood Type——12
  12. CDRAF之Service mesh
  13. flutter的webview案例
  14. ubuntu系统安装微信小程序开发工具
  15. MySQL 8.0的关系数据库新特性详解
  16. 一本通1649【例 2】2^k 进制数
  17. echarts 与 百度地图bmap结合系列: 如何设置地图缩放级别和监听缩放事件
  18. DotNetBar如何控制窗体样式
  19. CDMA LTE FAQ2
  20. 心情烦闷annoying,贴几个图!唉!annoying

热门文章

  1. Prometheus—告警altermanger
  2. 深度学习论文翻译解析(十九):Searching for MobileNetV3
  3. C++的智能指针你了解吗?
  4. Linux换行符和Windows换行符的区别与转换
  5. 2019牛客暑期多校训练营(第五场)E.independent set 1(状压dp)
  6. Educational Codeforces Round 89 (Rated for Div. 2) A. Shovels and Swords (贪心)
  7. C#之Dispose
  8. Python 往Excel写数据
  9. 【转】Kubernetes scheduler学习笔记
  10. codeforces 1045I Palindrome Pairs 【stl+构造】