Spark DynamicJoinSelection 规则根据AQE统计信息动态调整Join策略

背景

本文基于Spark 3.5.3

在Spark引入了AQE以后,Spark在运行的时候能够拿到运行时候的Shuffle统计信息,这些信息可以更好的来调整join的策略,当下规则下这种策略的调整是通过增加hint来进行控制的, 规则的目的是防止负优化。

分析

这里会有三种优化场景:
1. 检测大量空分区 → 添加 NO_BROADCAST_HASH HINT

对应的代码如下:

复制代码
 private def hasManyEmptyPartitions(mapStats: MapOutputStatistics): Boolean = {
    val partitionCnt = mapStats.bytesByPartitionId.length
    val nonZeroCnt = mapStats.bytesByPartitionId.count(_ > 0)
    partitionCnt > 0 && nonZeroCnt > 0 &&
      (nonZeroCnt * 1.0 / partitionCnt) < conf.nonEmptyPartitionRatioForBroadcastJoin
  }

这里有个配置spark.sql.adaptive.nonEmptyPartitionRatioForBroadcastJoin默认是0.2,

这种情况主要是在于AQE 中 等值join 转换 BroadcastHashJoinExec,防止 转化为BroadcastHashJoinExec,因为此时的shuffle数据已经有了,而且非空的分区数据比较少,直接shuffle join会更快,因为broadcast join还会有broadcast 的过程
2.分区数据小 → 添加 PREFER_SHUFFLE_HASH HINT

对应的代码如下:

复制代码
private def preferShuffledHashJoin(mapStats: MapOutputStatistics): Boolean = {
    val maxShuffledHashJoinLocalMapThreshold =
      conf.getConf(SQLConf.ADAPTIVE_MAX_SHUFFLE_HASH_JOIN_LOCAL_MAP_THRESHOLD)
    val advisoryPartitionSize = conf.getConf(SQLConf.ADVISORY_PARTITION_SIZE_IN_BYTES)
    advisoryPartitionSize <= maxShuffledHashJoinLocalMapThreshold &&
      mapStats.bytesByPartitionId.forall(_ <= maxShuffledHashJoinLocalMapThreshold)
  }

这里有spark.sql.adaptive.maxShuffledHashJoinLocalMapThreshold(默认是0),只要所有分区大小小于这个阈值,就使用hash join,因为如果使用SortMergeJoin的话,在join之前还会有Sort的操作,而hash join没有这个sort操作,数据量小的情况,hash join更快

*3.两者都满足 → 添加 SHUFFLE_HASH HINT

如果以上两种情况都满足,则直接加 SHUFFLE_HASH HINT

注意:以上发生的转换是在用户没有手动指定HINT的前提下

总体的决策逻辑流程如下:

复制代码
                              ┌─────────────────────────┐
                              │  Join 节点 (ExtractEquiJoinKeys) │
                              └───────────┬─────────────┘
                                          │
                    ┌─────────────────────┼─────────────────────┐
                    ▼                                         ▼
           检查 Left 子节点                            检查 Right 子节点
                    │                                         │
                    ▼                                         ▼
        ┌───────────────────────┐              ┌───────────────────────┐
        │ ShuffleQueryStageExec │              │ ShuffleQueryStageExec │
        │ 且 isMaterialized     │              │ 且 isMaterialized     │
        │ 且 mapStats.isDefined │              │ 且 mapStats.isDefined │
        └───────────┬───────────┘              └───────────┬───────────┘
                    │                                         │
         ┌──────────┴──────────┐                ┌──────────┴──────────┐
         ▼                     ▼                ▼                     ▼
   Many Empty Partitions?  All Partitions     Many Empty Partitions?  All Partitions
         │                     Small?                │                     Small?
         ▼                     ▼                    ▼                     ▼
    ─────────────       ─────────────        ─────────────       ─────────────
         │                     │                      │                     │
         ▼                     ▼                      ▼                     ▼
    demote BHJ:          prefer shuffle       demote BHJ:          prefer shuffle
    NO_BROADCAST_HASH    hash: PREFER_         hash: PREFER_        hash: PREFER_
                        SHUFFLE_HASH          SHUFFLE_HASH         SHUFFLE_HASH
相关推荐
YIN_尹5 小时前
【git原理与使用】git基本操作及底层原理(二)
大数据·git·elasticsearch
武子康5 小时前
H3-World 写了 CPU offload,为什么还不能保证塞进 48GB?
大数据·人工智能·深度学习
演艺大赏5 小时前
Doris 数据导出实战:SeaTunnel、EXPORT 与 OUTFILE 性能对比及 9.5 亿行写入故障复盘
大数据
isfox7 小时前
MapReduce 作业慢?别乱调参数,先找到瓶颈在哪
大数据
玩美数据8 小时前
市场调研数据分析与数据集驱动的行业格局变革深度解析
大数据·人工智能
微订校园外卖系统9 小时前
校园代取快递系统选型:现成系统与定制开发的技术核对项
大数据·运维·人工智能·外卖系统·本地生活·微订
挖掘狂人11 小时前
Token 都上双十一货架了,AI 电脑的账该怎么算?
大数据·程序员·ai编程
Black蜡笔小新12 小时前
消防控制室/配电房/中控室...视频汇聚平台EasyCVR岗位AI智能监测方案守住关键岗位
大数据·音视频·easycvr
大大大大晴天1 天前
每天认识一个组件:Apache Spark
大数据
七夜zippoe1 天前
Agent 上线第一天就炸了:6 个生产事故的根因分析与修复记录
大数据·ai·agent·根因分析·修复记录