Spark SQL Join操作的分区使用逻辑与性能优化疑问
Spark SQL Join 执行的分区规则与性能调优逻辑
先厘清两个极易混淆的“分区”概念
很多新手困惑的根源,是把两类完全独立的“分区”概念混在了一起:
- 你提到的
test1表存储的10个Parquet文件,是存储层的物理分片:是表写入时生成的文件级切分块,读取阶段默认每个分片对应1个输入Task,整个读表阶段的并行度和分片数完全一致,这也是你看到部分Stage仅用10个Task执行的核心来源。这类分片的数量、分布是写入时决定的,和运行时的Join逻辑没有强制绑定关系,可以被后续的计算流程调整。 - 你配置的
spark.sql.shuffle.partitions=200,是运行时Shuffle操作的默认输出分区数:所有需要触发Shuffle的算子(等值Join、分组聚合、去重等),在没有手动指定分区数的场景下,Shuffle环节最终写出的分区数默认就是200个,这也是你看到部分Stage用200个Task执行的核心来源。
等值Join场景下Spark的实际执行路径
不存在“选10个原表分区还是选200个Shuffle分区跑计算”的二选一,Spark会根据Join的类型走完全不同的流程:
场景1:触发默认的Shuffle Sort Merge Join(SMJ)
这是绝大多数大表等值Join的默认执行逻辑,流程完全是串行的、不存在可选路径:
- 第一阶段:按
test1原有的10个存储分片起10个Task,读取全表数据,针对每条数据计算Join Key的哈希值,把相同Key的数据写到对应的Shuffle分区里。写Shuffle分区时,默认按照spark.sql.shuffle.partitions配置的200个分区拆分数据。这一整个阶段的并行度是10个Task。 - 等两张表的所有数据都完成Shuffle写入后,作业进入下一个Stage:按200个Shuffle分区起200个Task,每个Task拉取对应分区下、来自两张表的相同Join Key的所有数据,排序后执行合并、Join计算。这一阶段的并行度是200个Task。
很多新手看到Spark UI上相邻的两个Stage,前一个跑读表用10个Task,后一个跑Join用200个Task,会以为Spark的执行逻辑飘忽不定,其实两个Stage根本就是同一条流水线的前后步骤。这种场景下根本不会直接用原表的10个分片跑Join计算:两张表的Join Key在原分片里是随机分布的,不通过网络把相同Key的数据挪到同一个计算节点,根本没法做本地匹配。
场景2:不触发Shuffle的Join
只有满足特定条件时,Spark才会跳过Shuffle流程,直接用原表的存储分片数跑计算,整段Join过程不会用到200个分区的配置:
- 广播Join:如果其中一张表的数据量小于广播阈值(默认10MB),Spark会把小表全量拉到所有Executor的内存中,大表直接按原有的10个存储分片起10个Task,逐片和本地内存中的小表做匹配计算。这种场景下全程没有Shuffle,Task数始终和大表的分片数保持一致。
- 分桶对齐Join:如果两张表在写入时,就按照完全相同的Join Key、完全相同的分桶数量做了CLUSTER BY存储,Spark会直接识别到两张表的Join Key分布已经完全对齐,不需要再做网络传输重分区,直接用原有的存储分片数起Task跑Join。比如test1按join_key聚簇成10个桶,另一张参与Join的表也是按相同join_key聚簇成10个桶,整个Join阶段就会用10个Task执行,不会触发Shuffle。
关于性能的常见误区
哪种分区方式性能更好?
没有绝对的最优值,核心判断标准是单分区的处理压力是否合理:
- 对走默认SMJ的场景,200个分区是Spark的默认值,适合绝大多数TB级以下规模的作业。如果每个Shuffle分区的单Task数据量超过1GB,会导致Task执行过慢、OOM风险升高,这时候适当提高分区数(比如调到400、800),把单分区数据量压到128MB-256MB的合理区间,就能明显提升性能。
- 但如果单分区的数据量已经只有几MB,还硬把分区数拉到数千个,会导致Task调度的固定开销远大于计算本身的耗时,反而会让作业变慢。
是不是要始终通过CLUSTER BY调高分區数提升Join性能?
完全错误:
- CLUSTER BY的本质是把原本Join时要做的Shuffle开销,提前挪到表写入阶段完成。它能带来收益的前提,是后续所有针对这张表的Join操作,都固定使用同一个Join Key、同一个分区数,才能真正省掉后续的Shuffle开销。
- 如果你不管表的实际数据量大小,盲目把CLUSTER BY的分区数调高,会直接生成大量小文件,后续读取阶段光扫文件、调度Task的开销就会大幅升高,完全是负收益。
- 如果你CLUSTER BY用的Key和后续Join的Key不匹配,或者另一张参与Join的表分桶规则不对齐,提前做的聚簇根本起不到省Shuffle的作用,甚至会因为分区数设置不合理,导致单分区数据量过大,拉低Join性能。
内容的提问来源于stack exchange,提问作者Matthew
相关产品推荐
相关产品推荐

