join底层是怎样实现的,应不应该使用join?

目录

问:join底层是怎样实现的?

时间复杂度分析:

情况1:tb1.id 和 tb2.id 字段都均无索引,时间复杂度为 N + N*M

情况2:tb1.id 和 tb2.id 字段都均有索引,时间复杂度为最大为N + N * logM,最小为 logN + logN * logM

结论:


问:join底层是怎样实现的?

select * from tb1 join tb2 on tb1.id=tb2.id 

以上面的 并表查询 举例,执行上面sql的流程如下:

  1. 扫描 tb1,将 tb1 中符合的所有数据,放入内存 join_buffer 中,由于是 select *,所以是将整行记录都放入内存中;
  2. 获取 tb1 中一行记录的 id 数据,去 tb2 中匹配;
  3. 重复步骤2,直至匹配完join_buffer中 tb1 的所有数据;
  4. 所有匹配得到的结果,合成结果集,返回给客户端;
  5. 其中 tb1 为驱动表,tb2为被驱动表;

以上流程的大概流程图如下:

时间复杂度分析:

假设 tb1 中有 N 条记录,tb2 中有 M 条记录

情况1:tb1.id 和 tb2.id 字段都均无索引,时间复杂度为 N + N*M
  1. 由于tb1.id没有索引,扫描 tb1 表时是全表扫描,时间复杂度是 N,join_buffer中也有 N 条记录;

  2. 之后,join_buffer 中的每条记录都要去 tb2 中匹配,由于没有tb2.id也没有索引,也需要全表扫描,N 条记录匹配,则需要 N * M 次扫描扫描, 时间复杂度为 N*M;

  3. 1,2步骤合起来,时间复杂度是 N + N * M,如果 N=10000,M=100000,则需要10亿次扫描,时间复杂度太高相当耗时。


情况2:tb1.id 和 tb2.id 字段都均有索引,时间复杂度为最大为N + N * logM,最小为 logN + logN * logM
  1. 由于 select * from tb1 join tb2 on tb1.id=tb2.id 没有过滤条件,所有不管 tb1.id 有没索引,都需要全表扫描,时间复杂度是 N,join_buffer中也有 N 条记录;

  2. join_buffer 中的每条记录都要去 tb2 匹配时,tb2.id有索引,则是索引树查询,每条记录的匹配时间为树高logM,N 条记录的时间复杂度则为 N * logM;

  3. 将 1,2步骤合起来,时间复杂度为 N + N * logM,mysql 中,一般存储10亿条数据的树高顶多为4,如果 N=10000,M=100000,则需要扫描 10000 + 10000 * log100000 ≈ 10000+10000*4 = 50000,扫描次数相对情况1少了非常多,由此可以看出索引在对性能优化上的巨大优势;

  4. 另外由时间复杂度  N + N * logM 可知,扫描行数小的表,简称小表,作为驱动表,优化效果更明显;

  5. 如果将 select * from tb1 join tb2 on tb1.id=tb2.id 改成 select * from tb1 join tb2 on tb1.id=tb2.id where tb1.id < 1000,则搜索tb1时可以采用树查询,时间复杂度为 logN,那么最终时间复杂度则为 logN + logN * logM,性能更一步优化;


结论:

综合情况1和情况2可知,如果并表查询的字段,有的不存在索引,则不推荐用并表查询,可以考虑分开表查询,拿到数据后再在程序里面做额外的处理;

如果并表查询的字段,均存在索引,可以考虑用并表查询。不过个人推荐还是不管什么情况都不要用并表查询,都采用分开查询后再在程序单独做处理的方式处理数据,让mysql尽量做更少的事,减少mysql负担。因为一般mysql的性能没业务层好拓展,性能比不上业务层的,将mysql做的事分担给业务层,能提高整体服务的吞吃量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值