为何阿里不推荐MySQL使用join?,java基础常见面试题

  • Index Nested-Loop Join算法的执行流程

TODO

该流程:

  1. 对驱动表t1做了全表扫描,需扫描100行

  2. 对于每一行R,根据a字段去t2查找,这是树搜索。由于构造数据一一对应,因此每次搜索过程都只扫描一行,共扫描100行

  3. 所以,整个执行流程,总扫描行数是200

所以能不能使用join?

假设不使用join,那就只能用单表查询:

select * from t1

查出t1所有数据,这里有100行。

循环遍历这100行数据:

  • 从每一行R取出字段a的值$R.a

  • 执行select * from t2 where a=$R.a

  • 把返回的结果和R构成结果集的一行

该查询过程,也扫描了200行,但共执行了101条语句,比join多了100次交互。而且客户端还要自己拼接SQL语句和结果。

这性能还不如直接join。

怎么选择驱动表?

=======================================================================

该示例中,驱动表t1走全表扫描,被驱动表t2走树搜索。

假设被驱动表行数M。每次在被驱动表查一行数据,要先搜索索引a,再搜索主键索引。每次搜索一棵树的时间复杂度log2M,所以在被驱动表上查一行的时间复杂度是 2*log2M

假设驱动表行数N,执行过程就要扫描驱动表N行,然后对每一行,到被驱动表上匹配一次。

因此整个执行过程,时间复杂度是 N + N*2*log2M。N扩大1000倍,扫描行数就会扩大1000倍;而M扩大1000倍,扫描行数扩大不到10倍。

可见,N严重影响扫描行数,应该让小表做驱动表。

小结

  • 使用join语句,性能比强行拆成多个单表执行SQL语句的性能要好

  • 如果使用join语句的话,需要让小表做驱动表。

这些结论的前提是“可以使用被驱动表的索引”。

若被驱动表用不上索引呢?

Simple Nested-Loop Join

======================================================================================

select * from t1 straight_join t2 on (t1.a=t2.b);

t2的b无索引,所以每次到t2去匹配时,就要做一次全表扫描。

但这样,该SQL就要扫描t2 100次,共扫描100*1000=10万行。若t1和t2都是10万行的表,就要扫描100亿行!

当然,MySQL也没有使用这个Simple Nested-Loop Join算法,而使用“Block Nested-Loop Join”算法,BNL。

Block Nested-Loop Join

=====================================================================================

被驱动表无可用索引时的算法流程:

  1. 把t1的数据读入线程内存join_buffer中,由于我们这个语句中写的是select *,因此是把整个表t1放入了内存

  2. 扫描t2,把t2中的每一行取出来,对比join_buffer数据,满足join条件的,作为结果集的一部分返回。

  • BNL执行流程

TODO

  • 不使用索引直接join的执行计划

t1、t2都做了次全表扫描,因此总扫描行数1100。由于join_buffer是以无序数组组织,因此对t2中的每一行,都要做100次判断,总共需要在内存中做的判断次数是:100*1000=10万次。

若使用SNL算法查询,扫描行数也是10万行。因此,时间复杂度一样的。但BNL算法的这10万次判断是内存操作,速度上会快很多,性能较好。

那么此时哪个表做驱动表呢?

假设小表的行数是N,大表的行数是M,则在该算法里:

  • 两个表都做一次全表扫描,总扫描行数:M+N

  • 内存中判断次数M*N

所以调换M和N无差异,所以选择哪个做驱动表,执行耗时都一样。

  • 若表t1是个大表,join_buffer放不下咋办?

join_buffer的由参数join_buffer_size设定,默认256k。若放不下t1的所有数据,就会分段放。

把join_buffer_size改成1200,再执行:

select *

from t1 straight_join t2 on (t1.a = t2.b);

执行过程如下:

  • 扫描t1,顺序读取数据行放入join_buffer,放完第88行join_buffer满了,继续第2步

  • 扫描t2,把t2中的每一行取出来,跟join_buffer中的数据做对比,满足join条件的,作为结果集的一部分返回

  • 清空join_buffer

  • 继续扫描t1,顺序读取最后的12行数据放入join_buffer中,继续执行第2步

step4、5,表示清空join_buffer再复用。这也能看出该算法的确是分块join。

此时由于t1被分成两次放入join_buffer,导致t2会被扫描两次。虽然分成两次放入join_buffer,但判断等值条件的次数不变,依然是(88+12)*1000=10万次。

此时如何选择驱动表?

假设,驱动表数据行数N,需分K(K不是常数,N越大K就会越大,因此把K表示为λ*N,显然λ的取值范围是(0,1))段完成,被驱动表数据行数M。

所以,该算法执行过程:

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

总结

如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了

《Java中高级核心知识全面解析》

小米商场项目实战,别再担心面试没有实战项目:

407989776)]

总结

如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了

《Java中高级核心知识全面解析》

[外链图片转存中…(img-wSJfONm3-1710407989776)]

小米商场项目实战,别再担心面试没有实战项目:

[外链图片转存中…(img-TainFUEh-1710407989777)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值