当前位置:首页 > 每日看点 > 正文内容

mysql 连表查询使用join 和 where 区别大么? 两个表用=和join连接什么区别?

卡卷网7个月前 (01-13)每日看点147

为什么很多人不推荐mysql连表join查询

join查询是什么?是连表查询,我们需要两个表的数据,就会使用join来进行连表。那么mysql里面是怎么连表的呢?它和我们自己查询出一张表的数据在遍历去查询另外一个表是不是一样呢?

join查询

join查询还可以写成left join,表示的是根据左边的表来查询右边的表。但实际上,优化器会进行优化,选择合适的表来做驱动表,不一定是左边的表。

Index Nested-Loop Join

NLJ算法,这是一种基于索引的算法,如果你的连表用到了索引,则会使用这个算法。

比如下面的查询语句:

b.uid字段有索引,并且假设a是小表,优化器选择了a表作为驱动表,b表作为被驱动表。

select * from a left join b on a.id = b.uid;

执行流程大致如下:

  1. 1. 读取表a的第一行数据
  2. 2. 使用表a的id去b表的索引树上查询到对应的b表id
  3. 3. 通过查询的b表id回表查询b表数据
  4. 4. 把a表和b表数据放在一起
  5. 5. 重复上面的步骤直到a表遍历完成
  6. 6. 返回数据

可以看到这和我们自己查询出一张表然后遍历查询过程是一样的。

但是它的优势是省略了多次连接数据库,连接数据库是比较耗费资源和时间的,这样来看,使用join是更加好的选择。当然前提是你的join被驱动表有索引。

这个过程扫描了整个表a和表a的id对应的每一行表b。假设a表的数据量是n,那么扫描了n + n行,当然不算回表。如果算上回表其实相当于n + n + n行。

我们再看一下这个算法的时间复杂度。

b+树中,定位一个记录的时间复杂度大约是log(m)。m是b表的数据行数。为什么这里使用了b表的数据行数而不是上面说的a表的行数呢,因为这里指的是b表索引树的时间复杂度,当然是跟b表索引树大小挂钩也就是b表数据大小挂钩了。如果在算上回表查询,那么时间复杂度大约是2log(m)。

a表要进行全表扫描,那么a表的时间复杂度就是n,再加上每一行要去b表中查询,那么去b表查询的时间就是n * 2log(m)。加起来就是n + (2nlog(m))。

这里面2是常量可以忽略不记,而且2是因为回表造成的,如果我们使用覆盖索引,那么这个2就可以去掉了。

nlog(m) 比 n小,所以显然n的影响是最大的。也就是说n越小,那么我们连表的速度就越快。所以我们连表的时候要使用更小的那张表作为驱动表,然后给被驱动表的连表字段上面加上索引或者覆盖索引。这样我们的连表其实还是很快的。

Block Nested-Loop Join

如果你的被驱动表字段上面没有索引,那么mysql就会使用另外一种算法。这个算法叫BNL算法。

本来没有索引的情况下,按照上面的流程应该是下面这样:

  1. 1. 读取表a的第一行数据
  2. 2. 使用表a的id去b表上进行全表扫描查询到对应的b表数据
  3. 3. 把a表和b表数据放在一起
  4. 4. 重复上面的步骤直到a表遍历完成
  5. 5. 返回数据

这样的话对于每一行表a的数据都要进行b表的全表扫描,也就是如果表a记为n行,表b记为m行,那么需要扫描n * m + n行数据。和上面的n + (2nlog(m))相比,可以看到慢了多少倍。

所以mysql使用了另外一种方法,也就是BNL算法,这个算法做了一下优化,流程变成了下面这样:

  1. 1. 读取表a的所有数据放入join buffer
  2. 2. 对表b进行全表扫描,然后把每一条数据和join buffer中的数据做对比。
  3. 3. 把满足条件的数据返回。

这样的话,也就是扫描了一遍表a和表b,那么需要扫描n + m行数据。可以看到比上面的n + (nm)来说少了n倍的扫描量。当然了,这个算法,还需要在join buffer中进行nm次对比数据,但是这样内存判断也要比上面的方法好很多。

同样的这个算法对于两张表都是全表扫描,也就无所谓上面说的需要小表做驱动表了,反正都一样,都要全表扫描。

join buffer存在内存中,那么他就有大小的限制,参数join_buffer_size就是限制join buffer大小的。默认值是256k。如果表a的数据大于join buffer的大小,那么就会分段,也就是分多次进行。

但是分多次执行就会有一个问题了。比如分成了c次,那么表b就要经历c次的全表扫描。所以内存允许,当然Join buffer大一点速度会快一些。

这样的话就不是上面的n + m了,而是变成了n + (c*m),c是根据join buffer大小和n的大小来决定的。如果n越小或者join buffer size越大,那么c就越小。也就是说,如果我们使用小表作为驱动表,那么在遇到数据量超过join buffer的时候,速度也会比较快。

总结

总的来说,Join的时候注意下面几点:

  • • 总是用小表作为驱动表比较好。
  • • 能加索引就在被驱动表join字段上面加索引,使用NLJ算法而不是BNL算法。
  • • 在没有索引,并且驱动表数据量过大时,可以通过调大join_buffer_size的值来加速连表查询。

扫描二维码推送至手机访问。

版权声明:本文由卡卷网发布,如需转载请注明出处。

本文链接:https://www.kajuan.net/ttnews/2025/01/9191.html

分享给朋友:

相关文章

如果我们没有自己的手机操作系统,会出现所谓的“卡脖子”“安全”问题吗?

如果我们没有自己的手机操作系统,会出现所谓的“卡脖子”“安全”问题吗?

前段时间某某高管在微博发文表示:“其实我觉得,中国人需要的不是一个自己的手机os,而是一个全国产的微信,再搭配一些辅助功能。”这算是“安卓开源”开源的代表了吧。然而打脸来的如此之快,10月30日消息,在Linux内核疑似大规...

有了Istio,开发还需要微服务架构吗?

有了Istio,开发还需要微服务架构吗?

Istio 是一个开源的服务网格(Service Mesh),通过它可以实现对服务间通信的管理和监控。对于那些本身没有设计为具备安全功能的传统应用程序,Istio 可以提供一个“透明”的安全保护层,而不需要对应用本身进行任何代码修改。 I...

Layui 不更新了么?

Layui 不更新了么?

layui2.8已经于今天正式发布了,新增优化了大量特性,这里按照layui更新日志的模块结构,详细为你一一介绍。基础风格调整新版调整主色调为#16baaa,在原有的墨绿基础上赋予了清新。更简单的构建构建代码更简单,除字体外,只有js和cs...

我爸讽刺我,写个破代码一年才十几万,他在工地带50个人,让我回去跟他干,写代码没出路,我该怎么选择?

我跟你一样的情况,本人现身说法,千万不要跟你爸干,我就是反面教材,现在想回去都回不去了,快十年没写代码了,再就是岁数大了,38岁了,35岁以上的码农根本就没公司愿意要,而且会受歧视。工程不好干,首先就是不合法,在法律层面,根本就没有包工头的...

荣耀magic 7 首发的应该都收到货了,感觉怎么样?

8号入手magic7,跟mate40pro比。优点:1、电池真耐用,充电块,华为电池也是新换的但是明显荣耀耐用;2、系统明显快多了,mate40pro下半年开始卡的不行,实在受不了了。3、声音、震动效果提升明显,指纹反应灵敏很多。 缺点:1...

华为纯血鸿蒙,从此天下三分了吗?

华为纯血鸿蒙,从此天下三分了吗?

万众期待的纯血版 HarmonyOS NEXT 终于是端上来了,主打一个自研,从里到外,从内核到架构,都是自研。用户的激情已经被点燃,可见大家对于纯血鸿蒙的期待,但是鸿蒙系统能不能真正与安卓、iOS三分天下呢?目前来说,还为时过早。iOS和...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。