3.3.19 etl加工过程中会阻塞在某个project和exchange,看上去是pipeline没有调度

【详述】问题详细描述
【背景】3.3.19 etl加工过程中会阻塞在某个project和exchange,看上去是pipeline没有调度 be的日志搜queryId没有异常信息。有完整的profile,chunk_size设的比较低只有128,调大到1024的时候可以成功跑完,可能是因为chunk_size的大小导致的吗?
【业务影响】
【是否存算分离】
【StarRocks版本】3.3.19
【集群规模】3fe 3be
【附件】


完整的profile
26a94458-0173-11f1-a575-00163e253cecprofile.txt (1.6 MB)

您遇到的查询阻塞问题,根源在于 极其低效的 SQL 写法不合理的 chunk_size 参数设置 共同作用导致的性能雪崩。

  1. 根本原因 (治本层面): SQL 结构问题 您的 SQL 查询通过 UNION ALL 组合了多个独立的子查询,每个子查询都从头完整地扫描了一遍大型 Hive 表 ads_fg_product_metric_month_info_f 。这种模式导致了数十次的重复数据读取,产生了海量的中间数据。这些中间数据在进行窗口函数计算时需要排序,其体量远超内存上限,因此触发了大规模的磁盘溢出(Spill),这是导致查询耗时近30分钟的核心原因。
  2. 直接诱因 (治标层面): chunk_size 设置不当 您将 chunk_size 设置为极小的 128 ,这是导致查询“卡死”在 PROJECTEXCHANGE 算子的直接原因。过小的 chunk_size 会:
  • 急剧增加调度开销 :处理的数据块数量增加了几十倍,导致 Pipeline 调度开销巨大。
  • 摧毁向量化计算优势 :StarRocks 的计算引擎在处理大块数据时效率最高,小 chunk 使其性能严重退化,尤其是在执行复杂的 CASE WHEN 表达式时。
  • 降低网络传输效率EXCHANGE 算子需要发送海量的小数据包,网络协议开销远大于实际数据传输,造成了数据流阻塞。

总结来说,低效的 SQL 创造了一个极其消耗资源的执行计划,而过小的 chunk_size 则彻底摧毁了 StarRocks 执行引擎的处理能力,两者叠加导致了最终的性能问题。

优化建议 ( prioritized)

1. (最高优先级) 调整 chunk_size 参数

立即将 chunk_size 参数从 128 恢复至 StarRocks 的默认值 4096 ,或者直接删除该参数设置。 这是解决当前执行阻塞、让查询能够稳定运行的最快方法。

  • 操作 : 在您的 ETL 任务配置或 Session 变量中,移除 SET chunk_size = 128 的设置。
  • 原因 : 恢复默认值可以充分发挥 StarRocks 向量化引擎和高效数据传输的优势,这是保证基本性能的底线。

2. (根本性优化) 重构 SQL 查询逻辑

为了从根本上解决性能问题,实现数量级的性能提升,并降低资源消耗,您必须重构 SQL。核心思想是: “一次读取,多次使用”

  • 操作 : 使用 公用表表达式 (CTE, WITH 子句) 将对 ads_fg_product_metric_month_info_f 的扫描提取出来,后续所有 UNION ALL 的分支都从这个 CTE 中读取数据。同时,将多个用于计算不同百分位的子查询合并为一个。
  • 重构后的 SQL 结构示例 :
-- 步骤1: 使用 CTE 将源表读取一次
WITH base_product_data AS (
    SELECT 
        sale_gmv, sale_count, avg_price, 
        category_name1, category_name2, category_name3, category_name4,
        yuce_market_category_id, month_date
    FROM lake.saas_hq_datalake.ads_fg_product_metric_month_info_f
    WHERE category_name1 IS NOT NULL OR category_name2 IS NOT NULL OR category_name3 IS NOT NULL OR category_name4 IS NOT NULL
),

-- 步骤2: 为每个 category_level 创建一个计算逻辑块,从 CTE 读取数据
category_level_1 AS (
    SELECT 
        DATE_FORMAT(t.month_date, '%Y-%m-%d') AS stat_date,
        '1' AS category_level,
        t.category_name1 AS category_name,
        -- ... 其他字段
        -- 步骤3: 在一个子查询内完成所有百分位计算,避免多次 JOIN
        MIN(CASE WHEN cum_ratio >= 0.25 THEN avg_price END) as cutoff_25,
        MIN(CASE WHEN cum_ratio >= 0.50 THEN avg_price END) as cutoff_50,
        -- ...
    FROM (
        SELECT *,
               SUM(sale_count) OVER (PARTITION BY category_name1, month_date ORDER BY avg_price) / 
               SUM(sale_count) OVER (PARTITION BY category_name1, month_date) AS cum_ratio
        FROM base_product_data
        WHERE category_name1 IS NOT NULL
    ) t
    GROUP BY t.month_date, t.category_name1 -- ...
),

category_level_2 AS (
    -- 类似上面的逻辑,但处理 category_name2
    SELECT ... FROM base_product_data WHERE category_name2 IS NOT NULL ...
)
-- ... 其他 category_level 的逻辑

-- 步骤4: 最后将所有处理好的结果 UNION ALL
SELECT ... FROM category_level_1
UNION ALL
SELECT ... FROM category_level_2
-- ...

预期效果

完成以上两步优化后,您可以预期:

  1. 查询耗时大幅缩短 :执行时间有望从 28分钟 级别降低到 数分钟 甚至更短。
  2. 磁盘溢出问题彻底解决 :由于中间结果集大大减小,内存将足以容纳所有计算,不再出现大规模的数据溢出。
  3. 集群资源消耗降低 :CPU 和内存使用会更加合理,减轻对整个集群的压力,提升 ETL 任务的稳定性。