遇到一个常见sql使用场景
insert overwrite table xxx(date='${hiveconf:date}')
select
*
from table1
union all
select
*
from table2
观察发现任务耗时慢,大概30多分钟,其中主要耗时花在合并小文件——每次执行完spark etl任务还会执行hive合并小文件合并,解决小文件过多的问题。
ALTER TABLE xxx PARTITION (date='${date}') concatenate
合并小文件前查看分区下的小文件数量,大概有4000-5000多个,看来是小文件太多,执行hive合并小文件命令的时候耗时了;合并完成后小文件数量40-50个。
解决方案:开窗函数+设置spark.sql.shuffle.partitions参数
1. 优化后的sql
insert overwrite table xxx(date='${hiveconf:date}')
select
……
,max(id) over(partition by id) as id
from
(
select
*
from table1
union all
select
*
from table2
)
2. 启动时设置参数
--conf spark.sql.shuffle.partitions,其默认大小为200。
--conf spark.sql.shuffle.partitions=50
3. 外层对表的主键进行分组开窗,其实就是最后一步进行shuffle。由于是主键,所以不存在数据倾斜问题,性能影响不大,数据重新均匀打散,再spark.sql.shuffle.partitions参数生成指定分区数量。
优化后,开窗会带来一定的性能消耗,但避免了再直一个任务做小文件合并,耗时从30多分钟缩小到五六分钟,实际中遇到类似问题,可以尝试此方法。