【Spark精讲】SparkSQL Join选择逻辑

SparkSQL Join选择逻辑 

先看JoinSelection的注释

        If it is an equi-join, we first look at the join hints w.r.t. the following order:
         1. broadcast hint: pick broadcast hash join if the join type is supported. If both sides
            have the broadcast hints, choose the smaller side (based on stats) to broadcast.
         2. sort merge hint: pick sort merge join if join keys are sortable.
         3. shuffle hash hint: We pick shuffle hash join if the join type is supported. If both
            sides have the shuffle hash hints, choose the smaller side (based on stats) as the
            build side.
         4. shuffle replicate NL hint: pick cartesian product if join type is inner like.
      
       If there is no hint or the hints are not applicable, we follow these rules one by one:
         1. Pick broadcast hash join if one side is small enough to broadcast, and the join type
            is supported. If both sides are small, choose the smaller side (based on stats)
            to broadcast.
         2. Pick shuffle hash join if one side is small enough to build local hash map, and is
            much smaller than the other side, and `spark.sql.join.preferSortMergeJoin` is false.
         3. Pick sort merge join if the join keys are sortable.
         4. Pick cartesian product if join type is inner like.
         5. Pick broadcast nested loop join as the final solution. It may OOM but we don't have
            other choice.

翻译下就是:

如果是等值join,就先看join hints,顺序如下 

  1. broadcast hint:join类型支持的话选择broadcast hash join,如果join的两边都有broadcast hint,选择小的(基于统计)一方去广播
  2. sort merge hint:如果join的key是可排序的,选择sort merge join
  3. shuffle hash hint:join类型支持的话选择shuffle hash join
  4. shuffle replicate NL hint:如果是inner like类型(inner或cross),则选择cartesian product join

如果没有hint或者hint的类型是不合适的,按如下顺序选择

  1. broadcast hash join:如果join的一方足够小,小到可以广播,同时join类型支持,如果两边都很小,选最小的(基于统计)
  2. shuffle hash join:如果join的一方足够小可以构建hash map,并且比另一端小很多,同时需要spark.sql.join.preferSortMergeJoin置为false
  3. sort merge join:如果join的key是可排序的
  4. cartesian product:如果join类型是inner like类型(inner或cross)
  5. broadcast nested loop join:打底策略,即便可能导致OOM但别无选择

注意:

  • hash join(broadcast hash join或者shuffle hash join)只支持等值Join,不支持full outer join
  • 小到可以广播指的是,小于spark.sql.autoBroadcastJoinThreshold的阈值(默认10MB)
  val AUTO_BROADCASTJOIN_THRESHOLD = buildConf("spark.sql.autoBroadcastJoinThreshold").doc("Configures the maximum size in bytes for a table that will be broadcast to all worker " +"nodes when performing a join.  By setting this value to -1 broadcasting can be disabled. " +"Note that currently statistics are only supported for Hive Metastore tables where the " +"command `ANALYZE TABLE <tableName> COMPUTE STATISTICS noscan` has been " +"run, and file-based data source tables where the statistics are computed directly on " +"the files of data.").version("1.1.0").bytesConf(ByteUnit.BYTE).createWithDefaultString("10MB")
  • shuffle hash join时要求一边比另一边小很多,小很多指的是3倍小于
    /*** Matches a plan whose output should be small enough to be used in broadcast join.*/private def canBroadcast(plan: LogicalPlan): Boolean = {plan.stats.sizeInBytes >= 0 && plan.stats.sizeInBytes <= conf.autoBroadcastJoinThreshold}/*** Matches a plan whose single partition should be small enough to build a hash table.** Note: this assume that the number of partition is fixed, requires additional work if it's* dynamic.*/private def canBuildLocalHashMap(plan: LogicalPlan): Boolean = {plan.stats.sizeInBytes < conf.autoBroadcastJoinThreshold * conf.numShufflePartitions}/*** Returns whether plan a is much smaller (3X) than plan b.** The cost to build hash map is higher than sorting, we should only build hash map on a table* that is much smaller than other one. Since we does not have the statistic for number of rows,* use the size of bytes here as estimation.*/private def muchSmaller(a: LogicalPlan, b: LogicalPlan): Boolean = {a.stats.sizeInBytes * 3 <= b.stats.sizeInBytes}

hash join为什么只支持等值join,同时不支持full outer join?

  • 这是由于hashmap的特性决定的,随机访问效率最高O(1),为了性能是不会通过hashmap进行遍历查找的。
  • 不支持full outer join 是因为小表做的是构建表,由于不是流式表,无法决定是否输出该行,完全是被动的

参考一下SparkSQL Join流程:

在Spark SQL中Join的实现都基于一个基本的流程,根据角色的不同,参与Join的两张表分别被称为"流式表"和"构建表",不同表的角色在Spark SQL中会通过一定的策略进行设定,通常来讲,系统会默认大表为流式表,将小表设定为构建表。

流式表的迭代器为StreamIterator,构建表的迭代器为BuildIterator。通过遍历StreamIterator中的每条记录,然后在BuildIterator中查找相匹配的记录,这个查找过程被称为Build过程,每次Build操作的结果为一条JoinedRow(A,B),其中A来自StreamIterator,B来自BuildIterator,这个过程为BuildRight操作,而如果B来自StreamIterator,A来自BuildIterator,则为BuildLeft操作。

对于LeftOuter、RightOuter、LeftSemi、RightSemi,他们的build类型是确定的,即LeftOuter、LeftSemi为BuildRight类型,RightOuter、RightSemi为BuildLeft类型。

cartesian join为什么会限制是inner like?

        def createCartesianProduct() = {if (joinType.isInstanceOf[InnerLike]) {Some(Seq(joins.CartesianProductExec(planLater(left), planLater(right), condition)))} else {None}}

可以看下JoinType的类,继承了InnerLike的一个是inner join,一个是cross join

object JoinType {def apply(typ: String): JoinType = typ.toLowerCase(Locale.ROOT).replace("_", "") match {case "inner" => Innercase "outer" | "full" | "fullouter" => FullOutercase "leftouter" | "left" => LeftOutercase "rightouter" | "right" => RightOutercase "leftsemi" | "semi" => LeftSemicase "leftanti" | "anti" => LeftAnticase "cross" => Crosscase _ =>val supported = Seq("inner","outer", "full", "fullouter", "full_outer","leftouter", "left", "left_outer","rightouter", "right", "right_outer","leftsemi", "left_semi", "semi","leftanti", "left_anti", "anti","cross")throw new IllegalArgumentException(s"Unsupported join type '$typ'. " +"Supported join types include: " + supported.mkString("'", "', '", "'") + ".")}
}sealed abstract class JoinType {def sql: String
}/*** The explicitCartesian flag indicates if the inner join was constructed with a CROSS join* indicating a cartesian product has been explicitly requested.*/
sealed abstract class InnerLike extends JoinType {def explicitCartesian: Boolean
}case object Inner extends InnerLike {override def explicitCartesian: Boolean = falseoverride def sql: String = "INNER"
}case object Cross extends InnerLike {override def explicitCartesian: Boolean = trueoverride def sql: String = "CROSS"
}case object LeftOuter extends JoinType {override def sql: String = "LEFT OUTER"
}case object RightOuter extends JoinType {override def sql: String = "RIGHT OUTER"
}case object FullOuter extends JoinType {override def sql: String = "FULL OUTER"
}case object LeftSemi extends JoinType {override def sql: String = "LEFT SEMI"
}case object LeftAnti extends JoinType {override def sql: String = "LEFT ANTI"
}
...
}

为什么Broadcast Nested Loop Join会OOM?

Broadcast Nested Loop Join需要广播数据集和嵌套循环,计算效率极低,对内存的需求也极大,因为不论数据集大小,都会有一个数据集被广播到所有executor上。

Cross Join优化案例

select /*+ mapjoin(b)*/a.*, sum(b.work_date) as '工作日'
from a
cross join 
work_date_dim b 
on b.begin_tm >= a.任务开始时间 
and b.end_tm < a.任务结束时间
group by ...

不加mapjoin的hint,执行结果就是特别慢!a表不到 10w, b表只有几千条,执行了30分钟还是不行!

加mapjoin的hint,不到 1分钟就执行完了。但是,注意b表不能太大。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四、C#高级特性(动态类型与Expando类)

在C#中&#xff0c;动态类型和ExpandoObject类是两个与运行时类型系统相关的特性&#xff0c;它们提供了更灵活的数据处理能力。 动态类型 动态类型是一种特殊的类型&#xff0c;允许你在运行时解析和操作对象的成员&#xff0c;而不需要在编译时知道这些成员的细节。使用动态…

通讯录排序(结构体)

输入n个朋友的信息&#xff0c;包括姓名、生日、电话号码&#xff0c;本题要求编写程序&#xff0c;按照年龄从大到小的顺序依次输出通讯录。题目保证所有人的生日均不相同。 输入格式: 输入第一行给出正整数n&#xff08;<10&#xff09;。随后n行&#xff0c;每行按照“…

【设计模式】解释器模式

一起学习设计模式 目录 前言 一、概述 二、结构 三、案例实现 四、优缺点 五、使用场景 总结 前言 【设计模式】——行为型模式。 一、概述 如上图&#xff0c;设计一个软件用来进行加减计算。我们第一想法就是使用工具类&#xff0c;提供对应的加法和减法的工具方法。 …

vue2中vuex详细使用

1.安装 说明&#xff1a;也就是版本号&#xff0c;一般vue2安装vuex3。 npm i vuex3.6.2 2.搭建架子 执行流程如下&#xff1a; 初始化状态&#xff1a;在state对象中定义了一个名为message的属性&#xff0c;并将其初始值设置为"启动"。 定义变更函数&#xff08…

Kafka(六)消费者

目录 Kafka消费者1 配置消费者bootstrap.serversgroup.idkey.deserializervalue.deserializergroup.instance.idfetch.min.bytes1fetch.max.wait.msfetch.max.bytes57671680 (55 mebibytes)max.poll.record500max.partition.fetch.bytessession.timeout.ms45000 (45 seconds)he…

前台收款单选择的保险公司 提示 往来户不属于该财务组织

前台收款单选择的保险公司 提示 往来户不属于该财务组织 问题避免 新增保险公司的时候&#xff0c;找一个已经存在的保险公司&#xff0c;利用多页签复制的方式来新增 保险公司 不然不能够自动生成 财务客户

selenium三大等待

一、强制等待 1.设置完等待后不管有没有找到元素&#xff0c;都会执行等待&#xff0c;等待结束后才会执行下一步 2.实例&#xff1a; driver webdriver.Chrome()driver.get("https://www.baidu.com")time.sleep(3) # 设置强制等待driver.quit() 二、隐性等待 …

Java与云平台开发:AWS、Azure与GoogleCloud

随着云计算的兴起&#xff0c;越来越多的企业和开发者开始将应用程序迁移到云端。AWS、Azure和Google Cloud是三家主要的云平台提供商&#xff0c;这些云平台提供各种计算资源和服务&#xff0c;帮助开发者构建、运行和扩展应用程序。在本文中&#xff0c;我们将重点讨论Java在…

Python处理音频文件两个非常重要库

pyaudio和sounddevice都是用于Python中音频处理和流的库&#xff0c;允许用户通过他们的API录制、播放和处理音频数据。下面是对这两个库的简要介绍&#xff1a; PyAudio PyAudio 提供了 Python 绑定到 PortAudio&#xff0c;这是一个跨平台的音频I/O库。它允许你很容易地使用…

Python+Torch+FasterCNN网络目标检测识别

程序示例精选 PythonTorchFasterCNN网络目标检测识别 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《PythonTorchFasterCNN网络目标检测识别》编写代码&#xff0c;代码整洁&#xff0c;规…

SQL Server从0到1——写shell

xp_cmdshell 查看能否使用xpcmd_shell&#xff1b; select count(*) from master.dbo.sysobjects where xtype x and name xp_cmdshell 直接使用xpcmd_shell执行命令&#xff1a; EXEC master.dbo.xp_cmdshell whoami 发现居然无法使用 查看是否存在xp_cmdshell: EXEC…

LeetCode 每日一题 Day 36 ||模拟/字典序(哈希策略)

383. 赎金信 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 示例 1&#xff1…

PyQT5+MySQL的学生信息管理系统【附源码,运行简单】

PyQT5MySQL的学生信息管理系统【附源码&#xff0c;运行简单】 总览 1、《学生成绩管理系统》1.1 方案设计说明书设计目标需求分析工具列表 2、详细设计2.1 登录2.2 程序主页面2.3 学生新增界面2.4 学生更改界面2.4 学生删除界面2.5 其他功能贴图 3、下载 总览 自己做的项目&a…

C语言 设置控制台字体及背景颜色

颜色函数SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),前景色 | 背景色 | 前景加强 | 背景加强); 前景色&#xff1a;数字0-15 或 FOREGROUND_XXX 表示 &#xff08;其中XXX可用BLUE、RED、GREEN表示&#xff09; 前景加强&#xff1a;数字8 或 FOREGROUND_INTENS…

使用Docker-Compose部署MySQL一主二从同步高可用MHA集群

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容准备mysql一主二从同步集群一主二从同步集群规划需要安装docker和docker-compose命令形式安装安装docker安装docker-compose 宝塔面板形式安装 部署Master节点的docker-compose.yaml文件部署MySQL从节点1的docker-compose.…

QOS(Quality of Service)基本原理及配置示例

个人认为&#xff0c;理解报文就理解了协议。通过报文中的字段可以理解协议在交互过程中相关传递的信息&#xff0c;更加便于理解协议。 由于QOS&#xff08;Quality of Service&#xff09;在报文上主要是更改特定字段进行流量的差异化服务&#xff0c;因此此处重点介绍各种服…

使用 C# Winfrom编写倒计时功能

在日常生活中&#xff0c;我们经常需要倒计时来提醒自己重要的时间节点&#xff0c;比如倒计时到达一个特定的日期和时间。介绍一个使用 C# 编写的倒计时应用程序的实现。 步骤一&#xff1a;应用程序的功能 它具有以下几个主要特点&#xff1a; 用户输入目标日期和时间&…

从零实现CLIP模型

1. 引言 CLIP代表语言图像对比预训练模型&#xff0c;是OpenAI于2021年开发的一个深度学习模型。CLIP模型中图像和文本嵌入共享相同的潜在特征空间&#xff0c;从而能够在两种模式之间直接进行对比学习。这是通过训练模型使相关的图像和文本更紧密地结合在一起&#xff0c;同时…

浅谈 JVM 类加载过程

&#x1f697;&#x1f697;&#x1f697;今天给大家分享的是HTTPS加密的工作过程。 清风的CSDN博客 &#x1f6e9;️&#x1f6e9;️&#x1f6e9;️希望我的文章能对你有所帮助&#xff0c;有不足的地方还请各位看官多多指教&#xff0c;大家一起学习交流&#xff01; ✈️✈…

四. 基于环视Camera的BEV感知算法-BEVDistill

目录 前言0. 简述1. 算法动机&开创性思路2. 主体结构3. 损失函数4. 性能对比总结下载链接参考 前言 自动驾驶之心推出的《国内首个BVE感知全栈系列学习教程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习下课程第四章——基于环视Cam…