You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

相似优化表关联小表耗时差异过大技术求助

两张Liquid Clustered表与小表Broadcast Join的性能差异问题

我有两张已优化的表,二者均基于同一列做Liquid Clustered,关联列相同。使用Broadcast Join将它们分别与另一张小表执行Inner Join时,耗时差异显著:

  • Table1:8TB、151列,耗时约2小时
  • Table2:5.5TB、90列,耗时仅约9分钟

另外我发现,Table1关联的执行摘要中没有针对大表的ColumnarToRow节点和第二个WholeStageCodegen节点。

表信息

Table1

  • 大小:8TB
  • 列数:151

Table2

  • 大小:5.5TB
  • 列数:90

执行摘要

与Table1关联的执行摘要

Completed in 6292595ms
Node(row)
*WholeStageCodegen(1)
-*(5):ColumnarToRow(253,461)
-*(6):Filter(253,461)
(1):Scan parquet **table1** (10,305,644,145)
(2):Filter(9,622,877,502)
(3):Project
(4):Scan parquet **smaller_table** (253,461)
(7):Exchange
(9):BroadcastHashJoin(28,206,425)
(10):Project
(11):WriteFiles
(12):ExecuteWriteIntoDeltaCommand
(13):ResultQueryStage
(23):AdaptiveSparkPlan

与Table2关联的执行摘要

Completed in 567963 ms
Node (row)
*WholeStageCodegen(1)
-*(6):ColumnarToRow (253,461)
-*(7):Filter (253,461)
*WholeStageCodegen(2)
-*(2):ColumnarToRow (19,364,719,597)
-*(3):Filter (17,548,253,303)
-*(4):Project
-*(10):BroadcastHashJoin (65,712,508)
-*(11):Project
(1):Scan parquet **table2** (19,364,719,597)
(5):Scan parquet **smaller_table**  (253,461)
(8):Exchange
(12):WriteFiles
(13):ExecuteWriteIntoDeltaCommand
(14):ResultQueryStage
(24):AdaptiveSparkPlan

问题分析与解决思路

核心差异:代码生成与列处理路径不同

从执行计划对比可以看出,Table2的大表扫描、过滤、投影、Join全被打包进第二个WholeStageCodegen节点,而Table1的大表处理(Scan、Filter、Project)是单独的非Codegen阶段,且无大表的ColumnarToRow转换,这是性能差距的关键:

  1. WholeStageCodegen缺失的影响:WholeStageCodegen会将多个算子合并生成原生Java代码,避免算子间的序列化/反序列化和数据拷贝,大幅提升执行效率。Table1的大表处理未进入Codegen,每个算子单独处理数据,带来大量额外开销。
  2. 列处理模式差异:Table2的大表先转成行式数据再走Codegen优化,而Table1直接以列式数据处理后续算子。虽然列式存储适合扫描,但Spark对行式数据的Codegen优化更成熟,无Codegen的列式处理性能反而下降。

可能的触发原因

  1. 列数过多导致Codegen失败:Table1有151列,远多于Table2的90列。Spark的WholeStageCodegen对生成的代码大小有隐性限制(默认JVM方法大小64KB),列数过多会导致生成代码超出限制,自动禁用Codegen,回退到非Codegen的列式处理路径。
  2. 统计信息不准确:尽管两张表都用了Liquid Clustered,但Table1的统计信息可能偏差较大,导致Spark优化器选择了非最优执行路径。
  3. 投影列复杂度高:如果Table1关联后的投影涉及大量列或复杂计算,也可能导致Codegen无法生效。

验证与解决步骤

  1. 检查Codegen日志:开启spark.sql.codegen.logLevel=DEBUG,运行查询后查看是否有Codegen failed日志,确认是否因列数过多导致Codegen失败。
  2. 调整Codegen参数:若为方法大小限制问题,可调大spark.sql.codegen.maxMethodCodeSize(如设为128000),允许生成更大的方法代码,让Table1的大表处理进入Codegen阶段。
  3. 裁剪列:查询中只保留需要的列,减少Table1的列处理数量,降低Codegen的代码大小压力。
  4. 更新表统计信息:执行ANALYZE TABLE table1 COMPUTE STATISTICS FOR ALL COLUMNS,让Spark优化器能更准确地选择执行计划。

内容的提问来源于stack exchange,提问作者user3648566

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 07:22:43