Spark 自适应查询执行(AQE)

Spark AQE

目前,距离 Spark 3.0 版本的发布已经将近一年的时间了,这次版本升级添加了自适应查询执行(AQE)、动态分区剪裁(DPP)和扩展的 Join Hints 等新特性。利用好这些新特性,可以让我们的性能调优如虎添翼。因此,我会用三讲的时间和你聊聊它们。今天,我们先来说说 AQE。

我发现,同学们在使用 AQE 的时候总会抱怨说:“AQE 的开关打开了,相关的配置项也设了,可应用性能还是没有提升。”这往往是因为我们对于 AQE 的理解不够透彻,调优总是照葫芦画瓢,所以这一讲,我们就先从 AQE 的设计初衷说起,然后说说它的工作原理,最后再去探讨怎样才能用好 AQE。

Spark 为什么需要 AQE

在 2.0 版本之前,Spark SQL 仅仅支持启发式、静态的优化过程

启发式的优化又叫 RBO(Rule Based Optimization,基于规则的优化),它往往基于一些规则和策略实现,如谓词下推、列剪枝,这些规则和策略来源于数据库领域已有的应用经验。也就是说,启发式的优化实际上算是一种经验主义。

经验主义的弊端就是不分青红皂白、胡子眉毛一把抓,对待相似的问题和场景都使用同一类套路。Spark 社区正是因为意识到了 RBO 的局限性,因此在 2.2 版本中推出了 CBO(Cost Based Optimization,基于成本的优化)。

CBO 的特点是“实事求是”,基于数据表的统计信息(如表大小、数据列分布)来选择优化策略。CBO 支持的统计信息很丰富,比如数据表的行数、每列的基数(Cardinality)、空值数、最大值、最小值和直方图等等。因为有统计数据做支持,所以 CBO 选择的优化策略往往优于 RBO 选择的优化规则。

但是,CBO 也面临三个方面的窘境:“窄、慢、静”。窄指的是适用面太窄,CBO 仅支持注册到 Hive Metastore 的数据表,但在大量的应用场景中,数据源往往是存储在分布式文件系统的各类文件,如 Parquet、ORC、CSV 等等

慢指的是统计信息的搜集效率比较低。对于注册到 Hive Metastore 的数据表,开发者需要调用 ANALYZE TABLE COMPUTE STATISTICS 语句收集统计信息,而各类信息的收集会消耗大量时间。

静指的是静态优化,这一点与 RBO 一样。CBO 结合各类统计信息制定执行计划,一旦执行计划交付运行,CBO 的使命就算完成了。换句话说,如果在运行时数据分布发生动态变化,CBO 先前制定的执行计划并不会跟着调整、适配。

这里我们用Broadcast为例子进行说明,如果基表的存储尺寸小于广播阈值,那么无需开发者显示调用 broadcast 函数,Spark SQL 同样会选择 Broadcast Join 的策略,在基表之上创建广播变量,来完成两张表的数据关联

那么问题来了,广播阈值是什么,它是怎么定义的呢?广播阈值实际上就是一个标记存储尺寸的数值,它可以是 10MB、也可是 1GB,等等。广播阈值由如下配置项设定,只要基表小于该配置项的设定值,Spark SQL 就会自动选择 Broadcast Join 策略。

image-20240731215434227

广播阈值的默认值为 10MB。一般来说,在工业级应用中,我们往往把它设置到 2GB 左右,即可有效触发 Broadcast Join。广播阈值有了,要比较它与基表存储尺寸谁大谁小,Spark SQL 还要还得事先计算好基表的存储尺寸才行。那问题来了,Spark SQL 依据什么来计算这个数值呢?

这个问题要分两种情况讨论:如果基表数据来自文件系统,那么 Spark SQL 用来与广播阈值对比的基准,就是基表在磁盘中的存储大小。如果基表数据来自 DAG 计算的中间环节,那么 Spark SQL 将参考 DataFrame 执行计划中的统计值,跟广播阈值做对比,如下所示。

val df: DataFrame = _
// 先对分布式数据集加Cache
df.cache.count
 
// 获取执行计划
val plan = df.queryExecution.logical

// 获取执行计划对于数据集大小的精确预估
val estimated: BigInt = spark
.sessionState
.executePlan(plan)
.optimizedPlan
.stats
.sizeInBytes

到这里,你也许会有点不耐烦:“何必这么麻烦,又要设置配置项,又要提前预估基表大小,真是麻烦!还不如用上一讲提到的 broadcast 函数来得干脆!”从开发者的角度看来,确实 broadcast 函数用起来更方便一些。不过,广播阈值加基表预估的方式,除了为开发者提供一条额外的调优途径外,还为 Spark SQL 的动态优化奠定了基础。

所谓动态优化,自然是相对静态优化来说的。在 3.0 版本之前,对于执行计划的优化,Spark SQL 仰仗的主要是编译时(运行时之前)的统计信息,如数据表在磁盘中的存储大小,等等。因此,在 3.0 版本之前,Spa

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值