善用Grouping Sets 提升代码效率

使用Grouping Sets可按照多个不同的维度组合进行聚合,减少了繁琐的代码,提升整体计算的效率。

比如,需要对国家,省份,城市各维度进行聚合时候,可能会这么写:

select '国家' as gep_type,country as geo_name,count(*) as cnt from tbl group by country
union all 
select '省份' as gep_type,province as geo_name,count(*) as cnt from tbl group by province
union all 
select '城市' as gep_type,city as geo_name,count(*) as cnt from tbl group by city
;

或者这么写:

select country,province,city,count(*)  as cnt from tbl group by country,province,city
union all
select country,province,'ALL' as city,count(*)  as cnt from tbl group by country,province
union all
select country,'ALL' as province,'ALL' as city,count(*)  as cnt from tbl group by country
;

无论哪种方式都会用到union all,而通过grouping sets,我们可以这么写:

-- 1. 先把空值替换成'-',不然在聚合的时候会被当成'ALL'
with tmp as (
    select 
        coalesce(country, '-') as country
        ,coalesce(province, '-') as province
        ,coalesce(city, '-') as city
    from tbl
)
-- 2.对于非本维度组合的字段,以'ALL'填充
select 
 coalesce(country, 'ALL') as country
,coalesce(province, 'ALL') as province
,coalesce(city, 'ALL') as city
,count(*)  as cnt 
from 
tmp 
group by country,province,city -- 按country,province,city聚合
grouping sets(
    (country) --只按country聚合,等于country,count(*)
    ,(province) --只按province聚合,等于province,count(*)
    ,(city) --只按city聚合,等于city,count(*)
    
    ,(country,province) --按country,province聚合,等于country,province,count(*)
) 

有任何疑问都可以在下方留言,我会尽量进行解答!

希望本文对你有帮助,请点个赞鼓励一下作者吧~ 谢谢!

### 优化 SparkSQLGrouping Sets Expand 性能的方法 Spark SQL 的 `GROUPING SETS` 功能允许用户在一个查询中计算多个分组组合的结果。然而,这种功能可能会导致数据膨胀(data expansion),因为每增加一组 `GROUPING SETS` 都会使得中间结果集加倍[^1]。 为了提升 `GROUPING SETS` 在 Spark SQL 中的性能,可以考虑以下几个方面: #### 1. 减少输入数据规模 通过过滤不必要的记录来减少进入 `GROUPING SETS` 的原始数据量是一个有效的策略。可以在查询中加入更严格的条件语句以提前剔除无关的数据行。 ```sql SELECT col1, col2, SUM(value) FROM table_name WHERE condition_column = 'specific_value' -- 添加严格筛选条件 GROUP BY GROUPING SETS ((col1), (col2)); ``` #### 2. 调整 Shuffle Partition 数目 Shuffle 是 Spark 执行过程中开销较大的部分之一。适当调整 shuffle partition 的数量可以帮助平衡负载并提高效率。可以通过设置参数 `spark.sql.shuffle.partitions` 来控制分区数,默认值通常为 200,但对于大规模数据可能需要更大的数值。 ```scala // 设置合适的shuffle分区数目 spark.conf.set("spark.sql.shuffle.partitions", "500") ``` #### 3. 使用广播连接替代 Shuffle Join 如果某些表较小,则可利用广播变量机制代替常规 join 操作从而避免额外 shuffle 开支。这适用于存在维度表参与运算的情况。 ```sql -- 假设 dim_table 很小,适合广播 SET spark.sql.autoBroadcastJoinThreshold=10MB; -- 自定义阈值大小 SELECT t.col1, d.name, SUM(t.value) FROM fact_table AS t JOIN broadcast(dim_table) AS d ON t.dim_id=d.id GROUP BY GROUPING SETS((t.col1,d.name),(d.name)); ``` #### 4. 启用 Codegen Optimizer Rules 确保启用了 WholeStageCodegen 及其他相关 optimizer rules ,这些特性能够显著改善复杂聚合操作的整体表现。 ```scala // 确认启用codegen选项 spark.conf.set("spark.sql.codegen.wholeStage", "true") ``` #### 5. 数据倾斜处理 当遇到严重数据分布不均时,应采取措施缓解其影响比如动态分配资源或者手动拆解热点 key 。另外还可以尝试开启 skew join optimization 特性解决此类问题。 ```scala // 开启skew join优化支持 spark.conf.set("spark.sql.adaptive.skewedJoin.enabled","true") ``` 以上方法综合运用可以从不同角度有效降低由 `GROUPING SETS` 引的数据扩展效应带来的负担,并最终达到加速目的。 问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王义凯_Rick

遇见即是缘,路过就给个评论吧~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值