众所周知,Join的种类丰富:

按照**关联形式(**Join type)划分:

有内关联,外关联,左关联,右关联,半关联,逆关联等,由业务逻辑决定的关联形式决定了Spark任务的运行结果;

按照关联机制(Join Mechanisms)划分:

有NLJ(Nested Loop Join) , SMJ(Sort Merge Join)和HJ(Hash Join),由数据内容决定的实现机制,则决定了Spark任务的运行效率;

关联形式

Spark支持的关联形式:

关联形式 Join Type关键字
内连接 inner
左外关联 left / left outer / left_outer
右外关联 right/ right outer/right_outer
全外关联 outer/ full / full outer / full_outer
左半关联 left semi/ left_semi
左逆关联 left anti / left_anti
交叉关联 crossJoin

数据准备

import spark.implicits._
import org.apache.spark.sql.DataFrame// 创建员工信息表
val seq = Seq((1, "Mike", 28, "Male"), (2, "Lily", 30, "Female"), (3, "Raymond", 26, "Male"), (5, "Dave", 36, "Male"))
val employees: DataFrame = seq.toDF("id", "name", "age", "gender")// 创建薪资表
val seq2 = Seq((1, 26000), (2, 30000), (4, 25000), (3, 20000))
val salaries:DataFrame = seq2.toDF("id", "salary")// 左表
salaries.show/** 结果打印
+---+------+
| id|salary|
+---+------+
| 1| 26000|
| 2| 30000|
| 4| 25000|
| 3| 20000|
+---+------+
*/// 右表
employees.show/** 结果打印
+---+-------+---+------+
| id| name|age|gender|
+---+-------+---+------+
| 1| Mike| 28| Male|
| 2| Lily| 30|Female|
| 3|Raymond| 26| Male|
| 5| Dave| 36| Male|
+---+-------+---+------+
*/

内连接(Inner join)

内连接是默认关联形式,可以省略写成join. 左右表按照join key连接, 舍弃未匹配的行,仅仅保留左右表中满足关联条件的那些数据记录.

// 内关联
val jointDF: DataFrame = salaries.join(employees, salaries("id") === employees("id"), "inner")jointDF.show/** 结果打印
+---+------+---+-------+---+------+
| id|salary| id| name|age|gender|
+---+------+---+-------+---+------+
| 1| 26000| 1| Mike| 28| Male|
| 2| 30000| 2| Lily| 30|Female|
| 3| 20000| 3|Raymond| 26| Male|
+---+------+---+-------+---+------+
*/

外连接(Outer join)

val jointDF: DataFrame = salaries.join(employees, salaries("id") === employees("id"), "left")jointDF.show/** 结果打印
+---+------+----+-------+----+------+
| id|salary| id| name| age|gender|
+---+------+----+-------+----+------+
| 1| 26000| 1| Mike| 28| Male|
| 2| 30000| 2| Lily| 30|Female|
| 4| 25000|null| null|null| null|
| 3| 20000| 3|Raymond| 26| Male|
+---+------+----+-------+----+------+
*/

外连接的左右指的是不满足join条件的数据来自于哪张表,上述的"left"左外连接,就让第三行数据来自于左表.

半关联(semi join)

 // 左半关联
val jointDF: DataFrame = salaries.join(employees, salaries("id") === employees("id"), "leftsemi")jointDF.show/** 结果打印
+---+------+
| id|salary|
+---+------+
| 1| 26000|
| 2| 30000|
| 3| 20000|
+---+------+
*/

半关联是inner join的一半返回,left semi join返回左表数据, right semi join返回右表数据

逆关联(anti join)

// 左逆关联
val jointDF: DataFrame = salaries.join(employees, salaries("id") === employees("id"), "leftanti")jointDF.show/** 结果打印
+---+------+
| id|salary|
+---+------+
| 4| 25000|
+---+------+
*/

逆关联返回的是未关联上的行.

关联机制

假设我们将join表称为"驱动表",将被join的表称为"基表",基于这两个称呼:

spark的关联机制

join实现机制 工作原理 适用场景
Nested Loop Join 在驱动表与基表之上,使用嵌套的双层for循环实现关联,效率最低,算法复杂度为O(M*N) 其他策略不使用的情况
Sort Merge Join 首先将两张表排序,然后以双指针遍历的方式实现关联,关联阶段的算法复杂度为O(M+N) 两张表都按照join key排序的情况
Hash Join 关联过程分为两个阶段 Build + Probe , Build 使用Hash算法生成哈希表O(N),Probe 查表获得值O(M) 哈希表较小且易生成.

关联策略

Spark的关联策略对比

对比项 Shuffle Join Broadcast Join
实现原理 * 根据Join Keys 计算哈希值
* 将哈希值按照并行度(parallelism)取模
封装一张小表为广播变量,发送到所有Executor.
优点 不论数据的体量是大是小、不管内存是否足够,Shuffle Join 在功能上都能成功地完成数据关联的计算 通过分发较小数据表,SQL的执行性能高效.
适用场景 任何场景都能完成 广播表较小
前提条件 基表需要足够小(小于Excutor内存)
缺点 shuffle IO 带来的性能瓶颈

关联机制 x 关联策略

3种关联机制跟 2中关联策略的组合,出现了6中join.由于Broadcast SMJ < Broadcast HJ ,去掉毫无用武之处的Broadcast SMJ,余下了以下5种join方式.

join方式 原理 适用场景
Broadcast HJ 基表加工成哈希表,广播到所有Executor,内部查表连接 基表小,等值join查表快
Broadcast NLJ 广播小表,Excutor内部用双重循环连接 基表小,可以用于不等值join
Shuffle SMJ 因为Shuffle要按照join key排序,所以spark 优先选择SMJ 基表大
Shuffle HJ 因为SMJ的原因,Shuffle HJ基本不用 同Shuffle SMJ
Shuffle NLJ 两张表都比较大,而且join是非等值join 其他场景都不适用的情况

Spark 浅谈Spark中的各种join相关推荐

  1. mysql inner和left优化_浅谈mysql中的left join和inner join性能及优化策略

    前言 看一下 下面的sql语句:select * from a left join b on a.x = b.x left join c on c.y = b.y 这样的多个left join组合的时 ...

  2. 浅谈Spark应用程序的性能调优

    浅谈Spark应用程序的性能调优 :http://geek.csdn.net/news/detail/51819 下面列出的这些API会导致Shuffle操作,是数据倾斜可能发生的关键点所在  1. ...

  3. oracle hash join outer,CSS_浅谈Oracle中的三种Join方法,基本概念 Nested loop join: Outer - phpStudy...

    浅谈Oracle中的三种Join方法 基本概念 Nested loop join: Outer table中的每一行与inner table中的相应记录join,类似一个嵌套的循环. Sort mer ...

  4. python文件路径拼接多出斜杠_浅谈python中拼接路径os.path.join斜杠的问题

    浅谈python中拼接路径os.path.join斜杠的问题 调试程序的过程中,发现通过os.path.join拼接的路径出现了反斜杠 directory1='/opt/apps/upgradePac ...

  5. python的re2和re区别_浅谈Python中re.match()和re.search()的使用及区别

    1.re.match()fvk免费资源网 re.match()的概念是从头匹配一个符合规则的字符串,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None.fvk免费资源网 包含的参数如下: ...

  6. python读取图像数据流_浅谈TensorFlow中读取图像数据的三种方式

    本文面对三种常常遇到的情况,总结三种读取数据的方式,分别用于处理单张图片.大量图片,和TFRecorder读取方式.并且还补充了功能相近的tf函数. 1.处理单张图片 我们训练完模型之后,常常要用图片 ...

  7. js打印线程id_浅谈python中的多线程和多进程(二)

    原创:hxj7 本文继续分享一个关于python多线程和多进程区别的例子 前文<浅谈python中的多线程和多进程>中我们分享过一个例子,就是分别利用python中的多线程和多进程来解决高 ...

  8. 获得进程id_浅谈python中的多线程和多进程(二)

    原创:hxj7 本文继续分享一个关于python多线程和多进程区别的例子 前文<浅谈python中的多线程和多进程>中我们分享过一个例子,就是分别利用python中的多线程和多进程来解决高 ...

  9. 浅谈CTF中各种花式绕过的小trick

    文章目录 浅谈CTF中各种花式绕过的小trick 前言 md5加密bypass 弱比较绕过 方法一:0e绕过 方法二:数组绕过 强比较绕过 方法:数组绕过 md5碰撞绕过 方法:使用Fastcoll生 ...

最新文章

  1. java b2b b2c o2o分布式电子商务云平台
  2. springboot集成freemarker 配置application.properties详解
  3. 在RHEL5.0中用YUM解决RPM包的依赖关系
  4. 计算机内存知识txt,计算机新手必备内存实用知识.docx
  5. 机器学习常见知识点自查50问与答
  6. xhprof在windows下面的安装和使用[上](windows版本)
  7. 听说java又过气了?看我运用大数据分析2019年java发展趋势!
  8. JS工具类——Select操作类
  9. 分布式技术追踪 2018年第二期
  10. android 模拟器 403,Android403R2模拟器安装.doc
  11. 2018仲恺农业计算机大类录取,仲恺农业工程学院2019录取分数线预测
  12. 踩坑指南!anaconda新建环境出错解决!又是猛男落泪的一天!
  13. 「转录组」WGCNA实战原理两不误
  14. Python 中拼音库 PyPinyin 的使用
  15. 什么是软件验收测试?验收测试的标准和流程介绍
  16. 百度CarLife Android车机端黑屏问题
  17. 计算机键盘怎么换键,电脑修改键盘按键的方法
  18. python正则表达式——区间的表达方式
  19. MATLAB轨迹规划 发给ROS中机器人实现仿真运动
  20. 中国大学MOOC·Python网络爬虫与信息提取(一)

热门文章

  1. jmeter 如何开展性能测试
  2. -XX:+UseCompressedOops 与 -XX:-UseCompressedOops
  3. Yii2 framework学习笔记(五) -- 为后台更换皮肤
  4. 小程序毕业设计 基于微信旅游攻略小程序毕业设计开题报告功能参考
  5. cnm.sb个人主页开源一个特别好看的个人官网展示单页
  6. 理解字符串处理基础题
  7. js 弹出全屏窗效果
  8. 9.19 换钱问题
  9. 【SQL Server学习笔记】4:使用SSMS创建数据库表并完善表结构
  10. 通过JS取汉字拼音首字母