1. 连接类型

Spark JoinType定义有7种Join连接类型:

case "inner" => Inner //内连接
case "outer" | "full" | "fullouter" => FullOuter //全外连接
case "leftouter" | "left" => LeftOuter //左外连接
case "rightouter" | "right" => RightOuter //右外连接
case "leftsemi" | "semi" => LeftSemi //左半连接
case "leftanti" | "anti" => LeftAnti //左反连接
case "cross" => Cross //笛卡尔积

1.Inner Join:内连接,两表等值JoinKey连接

在这里插入图片描述

2.Full Outer Join:外连接,两表没有匹配的行自动补Null,是两个表行数的总和

在这里插入图片描述

3.Left Outer Join:左连接,左表上没有匹配上的行自动补Null

在这里插入图片描述

4.Right Outer Join:右连接,右表上没有匹配上的行自动补Null

在这里插入图片描述

5.Left Semi Join:只输出在连接关系上匹配的数据行即可

  • 等价于select T1 from T1 left join T2 where T2 is not null

  • 等价于select T1 from T1 inner join T2,与Inner Join区别:只关心匹配是否存在,而不返回被匹配表的具体数据
    在这里插入图片描述

6.Left Anti Join:输出左连接关系上没有匹配上的数据行

  • 等价于select T1 from T1 left join T2 where T2 is null
    在这里插入图片描述

7.Cross Join:笛卡尔积,是两个表行数的乘积

在这里插入图片描述

2.连接算法

1. Nested Loop Join嵌套循环连接(NLJ, Nested Loop Join):​​双循环结构,使用两个嵌套for循环依次扫描两表的数据记录判断

  • 外层for循环:负责遍历左表(驱动表)的每一条数据

  • 内层for循环:负责遍历右表(基表)的所有记录,依次判断JoinKey 是否满足关联条件
    在这里插入图片描述

2. Sort Merge Join排序归并连接(SMJ,Sort Merge Join):先排序+后归并,

  • 排序阶段:Join两表按照JoinKey升序排列,若数据已有序(或为索引),则可跳过该步骤

  • 归并阶段:双指针遍历,使用两个指针分别指向排序后的两表起始位置,逐个比较JoinKey

    • JoinKey相等:找到两表中所有连续相同键的行(称为块),生成这些块的笛卡尔积作为连接结果

    • JoinKey不等:移动较小键的指针,直到找到匹配的键或遍历结束
      在这里插入图片描述

Hash Join哈希连接(HJ,Hash Join):Build阶段+Probe阶段,核心:基于Hash Map实现构件表扫描复杂度将至O(1)

  • Build阶段:

    • 构建表(小表)的JoinKey应用哈希函数,生成哈希值

    • 将键和对应的行数据存入哈希表的对应​​桶(Bucket)​​中,若多个键哈希冲突,使用链表连续保存

  • Probe阶段:

    • 探测表(大表)的JoinKey应用哈希函数,找到对应的哈希桶

    • 在哈希桶内精准匹配键值,若匹配成功则合并结果

在这里插入图片描述

对比NestedLoopJoinSortMergeJoinHashJoin
时间复杂度O(N*M)O(N logN + M logN + N+M)O(N +M)(1.哈希表在内存:2.无哈希冲突)
空间复杂度0(1)(无额外存储)O(N+M)(排序内存/磁盘)O(M)(构建哈希表)
是否需要排序不需要需要预先排序不需要 (但需哈希分桶)
适用连接条件等值、非等值(如<,>)等值、范围(需排序后合并)仅等值连接 (依赖哈希碰撞)
内存消耗低中等 (排序占用)高 (需存储哈希表)
最佳数据规模小表驱动大表(尤其小表可放入内存)大数据集 (分布式友好)中等数据集(内存足够存哈希表)
分布式场景适用性差 (需跨节点全量数据循环)优(Spark默认选择)中等(需广播或分阶段处理哈希表)

2. Spark Join方式

分布式环境,两表的join计算增加网络分发,数据在网络中分发主要有两种方式:

  • Shuffle:两表数据在集群做全量的数据分发

  • Broadcast(广播):将小表封装到广播变量,大表数据无需移动,可在本地完成join计算

下图展示Spark的五种连接计算方式,默认连接策略为ShuffleSortMergeJoin,适合大规模数据且无需广播,连接策略的选择核心在JoinSelection 类实现。
在这里插入图片描述

连接方式连接条件支持Join类型是否Shuffle/Sort适用数据规模性能
Shuffle sort Merge等值ALLShuffle + Sort大规模中等
Cartesian Product等值/非等值仅inner/cross joinShuffle小表极差
Shuffle Hash Join等值ALLShuffle中等规模较优
Broadcast NestedLoop等值/非等值ALL无小表+非等值条件较差
Broadcast HashJoin等值不支持full join无小表+大表最优

3.连接树结构

连接树(Join Tree)是一个二叉树,刻画每个表的Join顺序,叶子节点代表被连接的表,非叶子节点代表Join算子,根据树形结构可分为:

  • 左深树(Left-Deep Tree):树形结构向左倾斜,Join节点的右侧只能是叶子节点,很多数据库默认将左深树作为Join Reorder的搜索空间

  • 右深树(Right-Deep Tree):树形结构向右倾斜,左深树的镜像,Join节点的左侧只能是叶子节点

  • 锯齿树(ZigZag Tree):介于左深树和右深树之间,叶子节点在左右节点交换

  • 浓密树(Bushy Tree):结构最灵活,表可以按照任意顺序Join连接
    在这里插入图片描述

更多推荐