写过或者学过 SQL 的人应该都知道 left join,知道 left join 的实现的效果,就是保留左表的所有信息,而后把右表往左表上拼接,若是拼不上就是 null。除了 left join 之外,还有 inner join、outer join、right join,这些不一样的 join 能达到的什么样的效果,你们应该都了解了,若是不了解的能够看看网上的帖子或者随便一本 SQL 书都有讲的。今天咱们不讲这些 join 能达到什么效果,咱们主要讲这些 join 的底层原理是怎么实现的,也就是具体的效果是怎么呈现出来的。数据库
join 主要有 Nested Loop、Hash Join、Merge Join 这三种方式,咱们这里只讲最广泛的,也是最好的理解的 Nested Loop,Nested Loop 翻译过来就是嵌套循环的意思,那什么又是嵌套循环呢?嵌套你们应该都能理解,就是一层套一层;那循环呢,你能够理解成是 for 循环。缓存
Nested Loop 里面又有三种细分的链接方式,分别是 Simple Nested-Loop Join、Index Nested-Loop Join、Block Nested-Loop Join,接下来咱们就分别去看一下这三种细分的链接方式。数据结构
在正式开始以前,先介绍两个概念:驱动表(也叫外表)和被驱动表(也叫非驱动表,还能够叫匹配表,亦可叫内表),简单来讲,驱动表就是主表,left join 中的左表就是驱动表,right join 中的右表是驱动表。一个是驱动表,那另外一个就只能是非驱动表了,在 join 的过程当中,其实就是从驱动表里面依次(注意理解这里面的依次)取出每个值,而后去非驱动表里面进行匹配,那具体是怎么匹配的呢?这就是咱们接下来说的这三种链接方式。oop
Simple Nested-Loop Join 是这三种方法里面最简单,最好理解,也是最符合你们认知的一种链接方式,如今有两张表 table A 和 table B,咱们让 table A left join table B,若是是用第一种链接方式去实现的话,会是怎么去匹配的呢?直接上图:
性能
上面的 left join 会从驱动表 table A 中依次取出每个值,而后去非驱动表 table B 中从上往下依次匹配,而后把匹配到的值进行返回,最后把全部返回值进行合并,这样咱们就查找到了 table A left join table B 的结果。是否是和你的认知是同样的呢?利用这种方法,若是 table A 有10行,table B 有10行,总共须要执行 10 x 10 = 100 次查询。.net
这种暴力匹配的方式在数据库中通常不使用。翻译
Index Nested-Loop Join 这种方法中,咱们看到了 Index,你们应该都知道这个就是索引的意思,这个 Index 是要求非驱动表上要有索引,有了索引之后能够减小匹配次数,匹配次数减小了就能够提升查询的效率了。3d
为何会有了索引之后能够减小查询的次数呢?这个其实就涉及到数据结构里面的一些知识了,给你们举个例子就清楚了。
blog
上图中左边就是普通列的存储方式,右边是树结构索引,什么是树结构呢?就是数据分布的像树这样一层一层的,树结构有一个特色就是左边的数据小于顶点的数,右边的数大于顶点的数,你看右图中,左边的数3是否是小于顶点6,右边的数7是否是大于顶点6;左边的数1是否是小于顶点3,右边的数4是否是大于顶点3。索引
假如咱们如今要匹配数值9,若是是左边这种数据存储方式的话,咱们须要从第一行依次匹配到最后一行才能找到数值9,总共须要匹配7次;可是若是咱们是用右边这种树结构索引的话,咱们先拿9和最上层顶点6去匹配,发现9比6大,咱们就去顶点的右边去找,再去和7匹配,发现9仍然比7大,再去7的右边找,就找到了9,这样咱们只匹配了3次就把咱们想要的9找到了。是否是相比匹配7次节省了不少时间。
数据库中的索引通常用 B+ 树,为了让你们更好的理解,我上面画的图只是最简单的一种树结构,而非真实的 B+ 树,可是原理是同样的。
若是索引是主键的话,效率会更高,由于主键必须是惟一的,因此若是被驱动表是用主键去链接,只会出现多对一或者一对一的状况,而不会出现多对多和一对多的状况。
理想状况下,用索引匹配是最高效的一种方式,可是在现实工做中,并非全部的列都是索引列,这个时候就须要用到 Block Nested-Loop Join 方法了,这种方法与第一种方法比较相似,惟一的区别就是会把驱动表中 left join 涉及到的全部列(不止是用来on的列,还有select部分的列)先取出来放到一个缓存区域,而后再去和非驱动表进行匹配,这种方法和第一种方法相比所须要的匹配次数是同样的,差异就在于驱动表的列数不一样,也就是数据量的多少不一样。因此虽然匹配次数没有减小,可是整体的查询性能仍是有提高的。