Spark 3.4.1中PySpark多列求和执行异常缓慢问题求助
问题原因拆解
1. 多列求和的表达式结构坑
你写的sum([F.col(f"col{i}") for i in range(50)])会生成嵌套的二元加法表达式树——比如50列求和,最终是((((col0+col1)+col2)+...)+col49)这种多层嵌套结构。列数≤20时,树的深度浅,优化器处理起来没压力;但列数≥25时,树的深度超过20层,后续优化器的递归处理开销会指数级上升。
2. Spark 3.4.1与3.1.2的优化器差异
Spark 3.1.2的表达式优化逻辑很简单,对这种嵌套加法树只做基础的类型检查和常量替换,遍历一次就搞定。但Spark 3.4.1升级了优化器,新增了SimplifyBinaryExpressions这类规则,会反复检查加法的关联性、交换性,尝试合并同类操作。但这套逻辑在处理深层嵌套树时,会对每个节点进行多次遍历——比如50列的话,遍历次数会飙升到上千次,直接拖慢执行速度,极端情况会因为重复处理陷入看似“无限执行”的状态。
3. Scala 2.13元组22限制的影响
你怀疑的Scala元组限制确实是诱因:Spark内部处理多列时,列数≤22会用Scala元组封装表达式,优化器能批量处理;但列数>22时,只能用Seq这类集合封装,而3.4.1的优化器对集合封装的表达式没做适配优化,反而触发了更复杂的递归逻辑,进一步放大了性能问题。而3.1.2对超过22列的场景处理逻辑简单,没额外开销,所以正常运行。
额外规避方案
除了你已经做的重构,还有两种更高效的写法:
- 直接用字符串表达式求和:
F.expr(" + ".join([f"col{i}" for i in range(50)])),这种方式生成的是扁平化表达式,优化器处理更快; - 转数组后求和:
df_data.withColumn("col_sum", F.array_sum(F.array([F.col(f"col{i}") for i in range(50)])))。
内容的提问来源于stack exchange,提问作者ja-bot
相关产品推荐
相关产品推荐

