Hive(Impala)中Insert Overwrite如何生成单个文件避免小文件
问题描述
执行以下INSERT语句向db.A_full表插入数据:
INSERT OVERWRITE db.A_full PARTITION (year, month, day) SELECT DISTINCT A.ID , A.doc_type , A.city , A.gender , A.age , A.year , A.month , A.day FROM db.A_parcial as A
其中db.A_parcial仅包含单日期数据,数据量约148MB,理论上目标分区应生成单个文件,但执行后通过SHOW PARTITIONS db.A_full发现该分区生成了138个小文件,如何避免小文件生成?
解决方案
1. 调整Shuffle分区数(最直接有效)
DISTINCT操作会触发Shuffle,默认的Shuffle分区数(如Spark默认200、Hive默认Reducer数)会导致生成大量小文件。针对148MB的数据,直接将Shuffle/Reducer数设为1即可:
-- Spark环境 SET spark.sql.shuffle.partitions=1; -- Hive环境 SET hive.exec.reducers.max=1; SET mapreduce.job.reduces=1; -- 执行原INSERT语句 INSERT OVERWRITE db.A_full PARTITION (year, month, day) SELECT DISTINCT A.ID , A.doc_type , A.city , A.gender , A.age , A.year , A.month , A.day FROM db.A_parcial as A
2. 开启Hive小文件自动合并
通过Hive的合并参数,让任务完成后自动将小文件合并为指定大小的文件:
-- 开启Map和Reduce阶段的文件合并 SET hive.merge.mapfiles=true; SET hive.merge.mapredfiles=true; -- 设置合并后单个文件的目标大小(示例为128MB) SET hive.merge.size.per.task=134217728; -- 当平均文件大小低于此值时触发合并(示例为64MB) SET hive.merge.smallfiles.avgsize=67108864; -- 执行原INSERT语句 INSERT OVERWRITE db.A_full PARTITION (year, month, day) SELECT DISTINCT A.ID , A.doc_type , A.city , A.gender , A.age , A.year , A.month , A.day FROM db.A_parcial as A
3. 避免不必要的Shuffle(如果适用)
如果db.A_parcial中的数据本身无重复,可直接去掉DISTINCT关键字,这样不会触发Shuffle,输出文件数会与源表的文件数一致(源表为单文件的话,目标也会是单文件):
INSERT OVERWRITE db.A_full PARTITION (year, month, day) SELECT A.ID , A.doc_type , A.city , A.gender , A.age , A.year , A.month , A.day FROM db.A_parcial as A
4. 手动指定数据分布(适合需保留DISTINCT的场景)
通过DISTRIBUTE BY将所有数据分配到同一个Reducer中,确保输出单个文件:
-- Hive环境设置Reducer数为1 SET mapreduce.job.reduces=1; INSERT OVERWRITE db.A_full PARTITION (year, month, day) SELECT DISTINCT A.ID , A.doc_type , A.city , A.gender , A.age , A.year , A.month , A.day FROM db.A_parcial as A DISTRIBUTE BY year, month, day; -- 按分区键分布,确保同一分区数据进入同一Reducer
内容的提问来源于stack exchange,提问作者Alejandro Salazar
相关产品推荐
相关产品推荐

