sparkSql join 关联机制

💐💐扫码关注公众号,回复 spark 关键字下载geekbang 原价 90 元 零基础入门 Spark 学习资料💐💐

join 实现机制

Join 有 3 种实现机制,分别是 NLJ(Nested Loop Join)、SMJ(Sort Merge Join)和 HJ(Hash Join)

NLJ:Nested Loop Join

对于参与关联的两张表,如 salaries 和 employees,按照它们在代码中出现的顺序,我们约定俗成地把 salaries 称作“左表”,而把 employees 称作“右表”。在探讨关联机制的时候,我们又常常把左表称作是“驱动表”,而把右表称为“基表”。一般来说,驱动表的体量往往较大,在实现关联的过程中,驱动表是主动扫描数据的那一方。而基表相对来说体量较小,它是被动参与数据扫描的那一方。

在 NLJ 的实现机制下,算法会使用外、内两个嵌套的 for 循环,来依次扫描驱动表与基表中的数据记录。在扫描的同时,还会判定关联条件是否成立,如内关联例子中的 salaries(“id”) === employees(“id”)。如果关联条件成立,就把两张表的记录拼接在一起,然后对外进行输出。

不难发现,假设驱动表有 M 行数据,而基表有 N 行数据,那么 NLJ 算法的计算复杂度是 O(M * N)。尽管 NLJ 的实现方式简单、直观、易懂,但它的执行效率显然很差。执行高效的 HJ 和 SMJ 只能用于等值关联,也就是说关联条件必须是等式,像 salaries(“id”) < employees(“id”) 这样的关联条件,HJ 和 SMJ 是无能为力的。相反,NLJ 既可以处理等值关联(Equi Join),也可以应付不等值关联(Non Equi Join),可以说是数据关联在实现机制上的最后一道防线。

SMJ:Sort Merge Join

SMJ 的实现思路是先排序、再归并。给定参与关联的两张表,SMJ 先把他们各自排序,然后再使用独立的游标,对排好序的两张表做归并关联。

具体计算过程是这样的:起初,驱动表与基表的游标都会先锚定在各自的第一条记录上,然后通过对比游标所在记录的 id 字段值,来决定下一步的走向。对比结果以及后续操作主要分为 3 种情况:

  • 满足关联条件,两边的 id 值相等,那么此时把两边的数据记录拼接并输出,然后把驱动表的游标滑动到下一条记录;
  • 不满足关联条件,驱动表 id 值小于基表的 id 值,此时把驱动表的游标滑动到下一条记录;
  • 不满足关联条件,驱动表 id 值大于基表的 id 值,此时把基表的游标滑动到下一条记录。

基于这 3 种情况,SMJ 不停地向下滑动游标,直到某张表的游标滑到尽头,即宣告关联结束。对于驱动表的每一条记录,由于基表已按 id 字段排序,且扫描的起始位置为游标所在位置,因此,SMJ 算法的计算复杂度为 O(M + N)。然而,计算复杂度的降低,仰仗的其实是两张表已经事先排好了序。但是我们知道,排序本身就是一项很耗时的操作,更何况,为了完成归并关联,参与 Join 的两张表都需要排序。

Sort Merge Join 没有内存方面的限制。不论是排序、还是合并,SMJ 都可以利用磁盘来完成计算。所以,在稳定性这方面,SMJ 更胜一筹。

HJ:Hash Join

HJ 的设计初衷是以空间换时间,力图将基表扫描的计算复杂度降低至 O(1)。

具体来说,HJ 的计算分为两个阶段,分别是 Build 阶段和 Probe 阶段。在 Build 阶段,在基表之上,算法使用既定的哈希函数构建哈希表,如上图的步骤 1 所示。哈希表中的 Key 是 id 字段应用(Apply)哈希函数之后的哈希值,而哈希表的 Value 同时包含了原始的 Join Key(id 字段)和 Payload。

在 Probe 阶段,算法依次遍历驱动表的每一条数据记录。首先使用同样的哈希函数,以动态的方式计算 Join Key 的哈希值。然后,算法再用哈希值去查询刚刚在 Build 阶段创建好的哈希表。如果查询失败,则说明该条记录与基表中的数据不存在关联关系;相反,如果查询成功,则继续对比两边的 Join Key。如果 Join Key 一致,就把两边的记录进行拼接并输出,从而完成数据关联。

Hash Join 的执行效率最高,这主要得益于哈希表 O(1) 的查找效率。不过,在 Probe 阶段享受哈希表的“性能红利”之前,Build 阶段得先在内存中构建出哈希表才行。因此,Hash Join 这种算法对于内存的要求比较高,适用于内存能够容纳基表数据的计算场景。

join 数据分发

在大数据的应用场景中,数据的处理往往是在分布式的环境下进行的,在这种情况下,数据关联的计算还要考虑网络分发这个环节。在分布式环境中,Spark 支持两类数据分发模式。一类是Shuffle,Shuffle 通过中间文件来完成 Map 阶段与 Reduce 阶段的数据交换,因此它会引入大量的磁盘与网络开销。另一类是广播变量(Broadcast Variables),广播变量在 Driver 端创建,并由 Driver 分发到各个 Executors。因此,从数据分发模式的角度出发,数据关联又可以分为 Shuffle Join 和 Broadcast Join 这两大类。

在分布式环境中,两张表的数据各自散落在不同的计算节点与 Executors 进程。因此,要想完成数据关联,Spark SQL 就必须先要把 Join Keys 相同的数据,分发到同一个 Executors 中去才行。以 Join Keys 为基准,两张表的数据分布保持一致,是 Spark SQL 执行分布式数据关联的前提。而能满足这个前提的途径只有两个:Shuffle 与广播。

Shuffle Join

对于参与 Join 的两张数据表,Spark SQL 先是按照如下规则,来决定不同数据记录应当分发到哪个 Executors 中去:

  • 根据 Join Keys 计算哈希值
  • 将哈希值对并行度(Parallelism)取模

Spark SQL 在默认情况下一律采用 Shuffle Join,原因在于 Shuffle Join 的“万金油”属性。也就是说,在任何情况下,不论数据的体量是大是小、不管内存是否足够,Shuffle Join 在功能上都能够“不辱使命”,成功地完成数据关联的计算。

Broadcast Join

Spark 不仅可以在普通变量上创建广播变量,在分布式数据集(如 RDD、DataFrame)之上也可以创建广播变量。这样一来,对于参与 Join 的两张表,我们可以把其中较小的一个封装为广播变量,然后再让它们进行关联。

在 Broadcast Join 的执行过程中,Spark SQL 首先从各个 Executors 收集 employees 表所有的数据分片,然后在 Driver 端构建广播变量 bcEmployees,构建的过程如下图实线部分所示。

可以看到,散落在不同 Executors 内花花绿绿的矩形,代表的正是 employees 表的数据分片。这些数据分片聚集到一起,就构成了广播变量。接下来,如图中虚线部分所示,携带着 employees 表全量数据的广播变量 bcEmployees,被分发到了全网所有的 Executors 当中去。在这种情况下,体量较大的薪资表数据只要“待在原地、保持不动”,就可以轻松关联到跟它保持之一致的员工表数据了。通过这种方式,Spark SQL 成功地避开了 Shuffle 这种“劳师动众”的数据分发过程,转而用广播变量的分发取而代之。

尽管广播变量的创建与分发同样需要消耗网络带宽,但相比 Shuffle Join 中两张表的全网分发,因为仅仅通过分发体量较小的数据表来完成数据关联,Spark SQL 的执行性能显然要高效得多。这种小投入、大产出,用极小的成本去博取高额的性能收益,可以说是“四两拨千斤”!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/541075.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【VUE】使用Vue和CSS动画创建滚动列表

使用Vue和CSS动画创建滚动列表 在这篇文章中&#xff0c;我们将探讨如何使用Vue.js和CSS动画创建一个动态且视觉上吸引人的滚动列表。这个列表将自动滚动显示项目&#xff0c;类似于轮播图的方式&#xff0c;非常适合用于仪表盘、排行榜或任何需要在有限空间内展示项目列表的应…

【Altium Designer 20 笔记】隐藏PCB上的信号线(连接线)

使用网络类隐藏特定类型的信号线 如果你想要隐藏特定类型的信号线&#xff08;例如电源类&#xff09;&#xff0c;你可以首先创建一个网络类。使用快捷键DC调出对象类浏览器&#xff0c;在Net Classes中右击添加类&#xff0c;并重命名&#xff08;例如为“Power”&#xff0…

【Qt 学习笔记】QWidget的geometry属性及window frame的影响

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ QWidget的geometry属性 文章编号&#xff1a;Qt 学习笔记 / 16 文章目…

spring boot学习第十七篇:OAuth2概述及使用GitHub登录第三方网站

0. 导言 我们在浏览器上可以访问成百上千个网站&#xff0c;使用每个网站的服务一般都要先注册账号&#xff0c;那么我们为了更好地记忆&#xff0c;一般都会在多个网站使用相同的账号和密码进行注册。那么问题就来了&#xff0c;如果在你注册的网站中有某些个网站的系统设计不…

C++进阶03 模板与群体数据

听课笔记简单整理&#xff0c;供小伙伴们参考~&#x1f95d;&#x1f95d; 第1版&#xff1a;听课的记录代码~&#x1f9e9;&#x1f9e9; 编辑&#xff1a;梅头脑&#x1f338; 审核&#xff1a;文心一言 目录 &#x1f433;课程来源 &#x1f40b;模板 &#x1f40b;8.…

小区烟火AI检测/楼道杂物堆积消防隐患AI智能识别方案

一、背景需求 据新闻报道&#xff0c;今年4月7日&#xff0c;安徽省合肥市肥东县一民房发生火灾&#xff0c;致1死11伤&#xff0c;起火点是“一楼楼道杂物间”。 因为小区居民楼楼道堆积大量杂物而导致的消防火灾事故也不在少数。楼道堆积杂物是一个长期存在的问题&#xff…

安装ODBC方法

1、运行 搜索 ODBC数据源管理程序 32位或者 64位 2、在用户DSN或者系统DSN选择添加&#xff08;建议前者&#xff09;&#xff0c;此处以添加access数据库的odbc驱动为例 3、安装成功

2024妈妈杯数学建模A 题思路分析-移动通信网络中 PCI 规划问题

# 1 赛题 A 题 移动通信网络中 PCI 规划问题 物理小区识别码(PCI)规划是移动通信网络中下行链路层上&#xff0c;对各覆盖 小区编号进行合理配置&#xff0c;以避免 PCI 冲突、 PCI 混淆以及 PCI 模 3 干扰等 现象。 PCI 规划对于减少物理层的小区间互相干扰(ICI)&#xff0c;增…

jenkins通过pipeline部署springboot项目

部署方案&#xff1a; 1、springboot项目不保存部署的pipeline或dockerfile构建脚本等与部署相关的问文件&#xff0c;业务项目只需关心业务&#xff0c;能够正常构建为jar包即可 2、新建一个代码仓库&#xff0c;用于保存项目需要构建的Jenkinsfile 3、jenkins配置pipeline地址…

Element ui 动态展示表格列,动态格式化表格列的值

需求 后台配置前端展示的表格列&#xff0c;遇到比如 文件大小这样的值&#xff0c;如果后台存的是纯数字&#xff0c;需要进行格式化展示&#xff0c;并且能控制显示的小数位数&#xff0c;再比如&#xff0c;部分列值需要加单位等信息&#xff0c;此外还有状态类&#xff0…

【心路历程】初次参加蓝桥杯实况

送给大家一句话&#xff1a; 寂静的光辉平铺的一刻&#xff0c;地上的每一个坎坷都被映照得灿烂。 – 史铁生 《我与地坛》 初次参加蓝桥杯有感 一点小小的震撼难评的做题过程A题 艺术与篮球问题描述解题 B 题 五子棋问题描述解题 C题 训练士兵问题描述解题 D题 团建解题 E题 …

基于SpringBoot+Vue的毕业设计管理系统(源码+文档+部署+讲解)

一.系统概述 二十一世纪我们的社会进入了信息时代&#xff0c;信息管理系统的建立&#xff0c;大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多&#xff0c;而在线管理系统刚好能满足这些需求&#xff0c;在线管理系统突破了传统管理方式的局限性。于是本文针…

【前端】layui table表格勾选事件,以及常见模块

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《前端》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 表格勾选事…

接口测试-Mock测试方法详解

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、关于Mock测试 1、什么是Mock测试&#xff1f; Mock 测试就是在测试过程中&#xff0c;对于…

Vue3整合wangEditor(富文本编辑器框架) 以及提供存储渲染方案

目录 概述 Vue3整合wagnEditor 图片的上传 图片的删除 文章存储 文章渲染 概述 实现功能&#xff1a;管理端使用富文本编辑器编写文章内容&#xff0c;将编辑好的文章存入数据库或服务器中&#xff0c;前端应用读取存储的文章内容作展示。 本文章能提供 ①Vue3整合wangEdi…

一款免费、开源、可批量识别的离线OCR软件,适用于 Windows7 x64及以上平台

免费&#xff1a;本项目所有代码开源&#xff0c;完全免费。方便&#xff1a;解压即用&#xff0c;离线运行&#xff0c;无需网络。高效&#xff1a;自带高效率的离线OCR引擎&#xff0c;内置多种语言识别库。灵活&#xff1a;支持命令行、HTTP接口等外部调用方式。功能&#x…

Android开发——控件

目录 TextView 注意&#xff1a; ​编辑带阴影的textview&#xff1a;&#xff08;一般用于给字体添加属性&#xff09; ​编辑 跑马灯效果的textview​编辑 Button (前几个常用&#xff09; Botton事件处理 EditText (文本框&#xff09; 如何获取文本框里面的内容…

统计学习方法概述

一、引言 随着AI的曙光逐渐普照IT界&#xff0c;众多曾经高深莫测的人工智能术语与理念&#xff0c;如监督学习、算法模型、回归分析等&#xff0c;已悄然融入广大信息技术人员的知识体系之中。老猿是个很传统的IT人&#xff0c;虽未深究这些新兴知识的精髓&#xff0c;却也在…

从零开始编写一个cmake构建脚本

简介 本文档介绍cmake构建脚本编写&#xff0c;包含的一些主要元素和命名规范。 cmake构建脚本编写步骤 cmake构建工具版本要明确 # 命令名字要小写&#xff0c;这条语句要求构建工具至少需要版本为3.12或以上 cmake_minimum_required (VERSION 3.12)工程名及库的版本号明确…

阿里面试总结 一

写了这些还是不够完整&#xff0c;阿里 字节 卷进去加班&#xff01;奥利给 ThreadLocal 线程变量存放在当前线程变量中&#xff0c;线程上下文中&#xff0c;set将变量添加到threadLocals变量中 Thread类中定义了两个ThreadLocalMap类型变量threadLocals、inheritableThrea…