Spark 3.0 - 自适应查询执行与实例

616 阅读4分钟

目录

阅读时间: 4 分钟

简介

自适应查询执行(AQE)是Spark 3.0最伟大的功能之一,它根据查询执行过程中收集的运行时统计数据重新优化和调整查询计划。

AQE的必要性

随着Spark的每个主要版本,它一直在引入新的优化功能,以便更好地执行查询,实现更高的性能。在spark 3.0之前,基于成本的优化使用表的统计数据来确定结构化查询的最有效的查询执行计划。但是,由于可能存在过时的统计数据,它已经成为一种次优的技术。因此,在Spark 3.0中,引入了自适应查询执行(Adaptive Query Execution)。

启用自适应查询执行

自适应查询执行在默认情况下是禁用的。我们可以通过以下设置改变该属性。

spark.conf.set("spark.sql.adaptive.enabled",true)

AQE的工作

  • AQE通过基于查询执行过程中收集的运行时统计数据调整查询计划来改善催化剂优化器的工作流程。
  • Spark将发送关于shuffle文件中数据的实际大小的统计数据
  • 对于下一阶段,它重新优化逻辑计划,动态切换连接策略,洗牌分区等。

AQE的特点

1.切换连接策略

Spark支持很多连接策略,但在所有策略中,广播哈希连接(BHJ)是使用Spark的高性能连接策略之一。该策略只在一个条件下使用,即其中一个连接的表足够小,可以在广播阈值内的内存中找到。默认的广播大小阈值为10mb。

在Spark 2.x中,连接策略的选择是基于对输入文件大小产生的数据的估计,这种估计并不总是准确的,因为过滤器和复杂的操作者可以干扰修改大小,同时当AQE被启用时,它在运行时基于最准确的连接关系大小重新扫描连接策略。

2**.减少shuffle后的分区。**

在spark3.0之前,开发者需要了解数据,因为Spark不提供最佳分区。所以在每次洗牌操作后,开发者需要重新分区,根据记录总数增加或减少分区。让我们想象一下,有人选择了错误的分区数量,这将导致大量的数据在网络内传输,增加开销并严重影响性能。

在Spark 3.0中,在作业的每个阶段之后,Spark都会通过查看已完成阶段的指标来动态地确定最佳分区数量。

在启用AQE之前。

正如你在下图中看到的,在没有启用AQE的情况下,需要200个分区进行洗牌操作。

启用AQE后。

spark.conf.set("spark.sql.adaptive.enabled",true)
spark.conf.set("spark.sql.adaptive.coalescePartitions.enabled",true)

同样的shuffle操作只需要4个Partition。

3.优化倾斜连接

数据倾斜是一个数据分布的问题。当处理集群上的大量数据时,有可能出现数据在各分区之间分布不均的情况,这反过来会大大降低查询的性能,尤其是连接。

AQE从shuffle文件的统计数据中自动检测到这种倾斜,并通过将分区分割成更小的子分区来处理,这些子分区将被分别连接到另一侧的相应分区中。

让我们通过例子来更好地理解。

  • 表A连接表B的例子,其中表A有一个分区A0明显大于它的其他分区。
  • 因此,斜向连接优化将把分区A0分成两个子分区
  • 将它们分别连接到表B的相应分区B0。
  • 如果没有这个优化,将有四个任务运行排序合并连接,其中一个任务需要更长的时间
  • 经过这次优化,将有五个任务运行连接。
  • 因此,每个任务花费的时间大致相同,从而使整体性能得到提高。

AQE带来的TPC-DS性能提升

下面是通过AQE提高性能最多的10个TPC-DS查询的图表。这些改进大多来自于动态分区凝聚以及动态连接策略切换。

要了解TPC-DS模式,请参考链接

总结

AQE是对Apache Spark优化的一个重要补充。它可以极大地加快你的查询速度。