hive小文件调优实践

本文详细介绍了Hive处理大量小文件的调优方法,包括使用distributeby分区函数、输入端小文件合并、map-only和mapReducejob输出小文件合并、减少Reduce数量、以及输出结果和中间过程小文件调优。通过实例展示了不同策略的效果,如数据重分区、合并小文件、设置reduce数量等,以优化Hive查询性能和HDFS存储效率。
摘要由CSDN通过智能技术生成

以最详细,生产实例的方式展现hive大量小文件的调优过程,包括:

小文件产生的原因

  • 动态分区使用不合理,动态分区插入的时候,误判导致产生大量分区,大量分区自然就产生大量小文件

  • reduce的数量设置的较多,到reduce处理时,会分配到不同的reduce中,会产生大量的小文件

  • 源数据文件本身就存在大量的小文件

小文件过多产生的影响

  • 首先从底层存储HDFS文件系统来讲,HDFS本身就不适合存储大量小文件,小文件过多会致使namenode元数据特别大, 占用太多内存,严重影响HDFS的性能

  • 对 hive 来讲,在进行查询时,每一个小文件都会当成一个块,启动一个Map task来完成,而一个Map task启动和初始化的时间远远大于逻辑处理的时间,就会形成很大的资源浪费。并且,同时可执行的Map task数量也是受限的。

hive distribute by分区函数应用调优

distribute by类似MR中partition(自定义分区),分区规则是根据分区字段的hash码与reduce的个数进行取余操作后,余数相同的分到一个区。

以表中字段分区

set hive.auto.convert.join=true;
set hive.auto.convert.join.noconditionaltask=true;
set hive.auto.convert.join.noconditionaltask.size=10000000;
set hive.mapjoin.smalltable.filesize=200000000;

set hive.merge.mapfiles = true;
set hive.merge.mapredfiles = true; 
set hive.merge.size.per.task = 256000000;
set hive.merge.smallfiles.avgsize = 256000000;
set hive.merge.orcfile.stripe.level=false;
set hive.merge.rcfile.block.level=false;

--指定tmp.tmp_01的文件存储格式,默认为textfile
set hive.default.fileformat = orc;

drop table if exists tmp.tmp_01;
create table tmp.tmp_01 
--STORED AS orc
as
SELECT
      a.item_sku_id 
FROM  (
            SELECT
                    item_sku_id,sku_name,brandname_cn,data_type
            FROM big_table 
            WHERE dt = '2022-02-15' AND brandname_cn = '汾酒'
            distribute by item_sku_id -- 大表以表中字段分组
      ) a --数据量远远大于10M
LEFT OUTER JOIN
      (     SELECT item_sku_id 
            FROM small_table 
            WHERE version = '1' AND normal_brandname_en = 'fenjiu' AND dt = '2022-02-15'
      ) b --数据量大小小于10M
ON a.item_sku_id = b.item_sku_id
WHERE b.item_sku_id IS NULL;

结果:

2022-02-16 23:03:47 INFO Table tmp.tmp_ljjtest02 stats: [numFiles=23, numRows=23, totalSize=5894, rawDataSize=2252]
2022-02-16 23:03:47 INFO Stage-1: Map: 18024  Reduce: 1009   Cumulative CPU: 377078.2 sec   HDFS Read: 193.287 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 4m18s539ms job_5690061100801_32622232
2022-02-16 23:03:47 INFO Stage-10: Map: 920   Cumulative CPU: 5431.21 sec   HDFS Read: 0.008 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 52s336ms job_5690061100801_32622707
2022-02-16 23:03:47 INFO Stage-4: Map: 832   Cumulative CPU: 1078.67 sec   HDFS Read: 0.001 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 31s273ms job_8766029101801_36250210
2022-02-16 23:03:47 INFO Total MapReduce CPU Time Spent: 4d10h33m8s80ms
2022-02-16 23:03:47 INFO Total Map: 19776  Total Reduce: 1009
2022-02-16 23:03:47 INFO Total HDFS Read: 193.296 GB  Written: 0.000 GB

结果分析:

以表中字段分区,如果数据不均匀,可能会造成数据倾斜。

以随机数分区

set hive.auto.convert.join=true;
set hive.auto.convert.join.noconditionaltask=true;
set hive.auto.convert.join.noconditionaltask.size=10000000;
set hive.mapjoin.smalltable.filesize=200000000;

set hive.merge.mapfiles = true;
set hive.merge.mapredfiles = true; 
set hive.merge.size.per.task = 256000000;
set hive.merge.smallfiles.avgsize = 256000000;
set hive.merge.orcfile.stripe.level=false;
set hive.merge.rcfile.block.level=false;

--指定tmp.tmp_01的文件存储格式,默认为textfile
set hive.default.fileformat = orc;

drop table if exists tmp.tmp_01;
create table tmp.tmp_01 
--STORED AS orc
as
SELECT
      a.item_sku_id 
FROM  (
            SELECT
                    item_sku_id,sku_name,brandname_cn,data_type
            FROM big_table 
            WHERE dt = '2022-02-15' AND brandname_cn = '汾酒'
            distribute by rand(100)-- 大表以随机数分组
      ) a --数据量远远大于10M
LEFT OUTER JOIN
      (     SELECT item_sku_id 
            FROM small_table 
            WHERE version = '1' AND normal_brandname_en = 'fenjiu' AND dt = '2022-02-15'
      ) b --数据量大小小于10M
ON a.item_sku_id = b.item_sku_id
WHERE b.item_sku_id IS NULL;

结果:

2022-02-16 22:53:00 INFO Table tmp.tmp_01 stats: [numFiles=3, numRows=23, totalSize=958, rawDataSize=2235]
2022-02-16 22:53:00 INFO Stage-1: Map: 18024  Reduce: 1009   Cumulative CPU: 372613.35 sec   HDFS Read: 193.289 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 5m32s865ms job_5690061100801_32621522
2022-02-16 22:53:00 INFO Stage-10: Map: 924   Cumulative CPU: 5424.53 sec   HDFS Read: 0.008 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 41s846ms job_5690061100801_32621870
2022-02-16 22:53:00 INFO Stage-4: Map: 858   Cumulative CPU: 1374.95 sec   HDFS Read: 0.001 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 43s592ms job_5690061100801_32621913
2022-02-16 22:53:00 INFO Total MapReduce CPU Time Spent: 4d9h23m32s830ms
2022-02-16 22:53:00 INFO Total Map: 19806  Total Reduce: 1009
2022-02-16 22:53:00 INFO Total HDFS Read: 193.298 GB  Written: 0.000 GB

结果分析:

以随机数分区,可以把数据从map端随机均匀的拆分给reduce端

总结

数据重分区(触发一个mr job),控制在map端如何拆分数据给reduce端,默认hash
distribute by item_sku_id 会导致数据倾斜
distribute by rand() 如果执行过程中其中一个reduce任务失败,可能会导致数据丢失或重复
distribute by rand(int seed) 指定随机种子,会得到一个稳定的随机数序列,可以避免数据不准确的问题

distribute by rand()的风险具体原理如下:

  • 部分reduce shuffle失败导致上游个别map task重新生成数据,如果shuffle分片逻辑不包含随机因子,会导致新生成的数据shuffle分片与之前不完全一致,进而导致部分数据重复读取或者数据丢失

  • reduce task从每个map task的结果文件中拉取对应分区的数据。数据在map阶段已经是分好区了,并且会有一个额外的索引文件记录每个分区的起始偏移量。所以reducetask取数的时候直接根据偏移量去拉取数据。

  • 新生成的shuffle分片内数据会丢数据,同时也可能包含已经分发到其他reducer的map阶段数据,导致数据重复分发。

    注意:
    rand(int seed) 是个稳定的随机数序列而不是固定的数值,从table列的角度来说,每一列都是不一样
    可以通过【select *,rand(1) as rand from t1】去验证


hive输入端小文件合并调优方式

输入端小文件合并设置:

--输入小文件合并,若读取小文件较多,则设置在map端进行小文件合并参数
set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;-- 执行Map前进行小文件合并
set hive.hadoop.supports.splittable.combineinputformat = true;
--其中一种方版本
set mapreduce.input.fileinputformat.split.maxsize = 256000000;
set mapreduce.input.fileinputformat.split.minsize =256000000;
set mapreduce.input.fileinputformat.split.minsize.per.node=256000000;
set mapreduce.input.fileinputformat.split.minsize.per.rack=256000000;
--另一种版本
SET mapred.max.split.size = 256000000; //设置mapper拆分大小
SET mapred.min.split.size = 256000000;
SET mapred.min.split.size.per.node = 256000000;
SET mapred.min.split.size.per.rack = 256000000;

根据hive的版本不同,不同的版本可能有些配置不一样,然后根据自己的实际集群情况进行设置。

map-only 和 mapReduce job输出小文件合并调优方式

开启输出结果小文件合并:
rcfile和orc需要特殊设置才能进行文级别的合并,parquet、textfile、sequencefile默认进行文件级别的合并

set hive.merge.mapfiles = true;--开启只有map(map-only)操作结束时小文件输出合并
set hive.merge.mapredfiles = true;--开启有map和reduce操作结束时小文件输出合并
set hive.merge.size.per.task = 256000000;--合并后每个文件的大小
set hive.merge.smallfiles.avgsize=256000000;--当输出文件的平均大小小于256000000时,启动一个独立的MR任务进行文件合并,触发小文件合并的阀值
set hive.merge.orcfile.stripe.level=false; --当这个参数设置为true,orc文件进行stripe Level级别的合并,当设置为false,orc文件进行文件级别的合并,默认为true。
set hive.merge.rcfile.block.level=false;--当这个参数设置为true,rcfile文件进行block Level级别的合并,当设置为false,rcfile文件进行文件级别的合并,默认为true。

map-only操作结束时小文件合并

set hive.auto.convert.join=true;
set hive.auto.convert.join.noconditionaltask=true;
set hive.auto.convert.join.noconditionaltask.size=10000000;
set hive.mapjoin.smalltable.filesize=200000000;

set hive.merge.mapfiles = true; -- map-only结束时小文件合并
set hive.merge.mapredfiles = false; -- MR操作结束时,不合并小文件
set hive.merge.size.per.task = 256000000;
set hive.merge.smallfiles.avgsize = 256000000;
set hive.merge.orcfile.stripe.level=false;
set hive.merge.rcfile.block.level=false;

--指定tmp.tmp_01的文件存储格式,默认为textfile
set hive.default.fileformat = orc;

drop table if exists tmp.tmp_01;
create table tmp.tmp_01 
--STORED AS orc
as
create table tmp.tmp_01 as
SELECT
      item_sku_id
FROM
      cdm.cdm_goods_360buy_act_basic_da
WHERE
      dt = '2022-02-15'
      AND barndname_cn = '汾酒'

结果:

2022-02-17 14:45:37 INFO Table tmp.tmp_ljjtest021 stats: [numFiles=1, numRows=18415, totalSize=110953, rawDataSize=1762456]

结果分析:

【set hive.merge.mapfiles = true;】控制map-only操作结束时的小文件合并

mapReduce操作结束时小文件合并

set hive.auto.convert.join=true;
set hive.auto.convert.join.noconditionaltask=true;
set hive.auto.convert.join.noconditionaltask.size=10000000;
set hive.mapjoin.smalltable.filesize=200000000;

set hive.merge.mapfiles = false; -- map-only结束时小文件不合并
set hive.merge.mapredfiles = true; -- MR操作结束时,合并小文件
set hive.merge.size.per.task = 256000000;
set hive.merge.smallfiles.avgsize = 256000000;
set hive.merge.orcfile.stripe.level=false;
set hive.merge.rcfile.block.level=false;

--指定tmp.tmp_01的文件存储格式,默认为textfile
set hive.default.fileformat = orc;

drop table if exists tmp.tmp_01;
create table tmp.tmp_01 
--STORED AS orc
as
SELECT
      a.item_sku_id 
FROM  (
            SELECT
                    item_sku_id,sku_name,brandname_cn,data_type
            FROM big_table 
            WHERE dt = '2022-02-15' AND brandname_cn = '汾酒'
      ) a --数据量远远大于10M
LEFT OUTER JOIN
      (     SELECT item_sku_id 
            FROM small_table 
            WHERE version = '1' AND normal_brandname_en = 'fenjiu' AND dt = '2022-02-15'
      ) b --数据量大小小于10M
ON a.item_sku_id = b.item_sku_id
WHERE b.item_sku_id IS NULL;

结果:

2022-02-16 23:12:45 INFO Table tmp.tmp_01 stats: [numFiles=1, numRows=23, totalSize=426, rawDataSize=2235]

结果分析:

【set hive.merge.mapredfiles = true;】控制mapReduce和mapjoin操作结束时的小文件合并

总结

这里需要注意mapjoin操作,虽然只触发了map操作,而没有触发reduce操作。
但这是优化的结果,本质上还是mapReduce任务,因此被【set hive.merge.mapredfiles = true;】参数控制。

减少Reduce数量小文件的调优方式

reduce 的个数决定了输出的文件的个数,因此能够调整reduce的个数控制hive表的文件数量,
hive中的分区函数 distribute by 控制MR中partition分区,即reduce的数量,结合分区函数让数据更加均衡的分配到每一个reduce。

  • 设置reduce的数量有两种方式,第一种是直接设置reduce个数
    set mapreduce.job.reduces=10;

  • 第二种是设置每一个reduce的大小,Hive会根据shuffle后数据量总的大小确定reducer个数
    set hive.exec.reducers.bytes.per.reducer=5120000000; – 默认是1G,设置为5G

输出结果减少小文件的数量

set mapreduce.job.reduces=10;
insert overwrite table A partition(dt)
select * from B
distribute by rand(1);

解释: 如设置reduce数量为10,则使用 rand(1), 随机生成一个数 x % 10 ,
这样数据就会随机进入 reduce task中,防止出现有的文件太大或太小

中间过程减少小文件的数量

set hive.exec.reducers.bytes.per.reducer=5120000000; -- 默认是1G,设置为5G
SELECT
      a.* 
FROM  (
            SELECT
                    item_sku_id,sku_name,brandname_cn,data_type
            FROM big_table 
            WHERE dt = '2022-02-15' AND brandname_cn = '汾酒'
            distribute by rand(1) -- 分组
      ) a --数据量远远大于10M
LEFT OUTER JOIN
      (     SELECT item_sku_id 
            FROM small_table 
            WHERE version = '1' AND normal_brandname_en = 'fenjiu' AND dt = '2022-02-15'
      ) b --数据量大小小于10M
ON a.item_sku_id = b.item_sku_id
WHERE b.item_sku_id IS NULL

解释: 如果map 到reduce端中间过程shuffle后总的数据量大小为50G,则分区数为10,则使用 rand(1), 随机生成一个数 x % 10 ,这样数据就会随机进入 reduce task中,防止中间过程的文件太大或太小

hive输出结果小文件问题调优思路

执行mapjoin,不合并小文件,不重分区

set hive.auto.convert.join=true;
set hive.auto.convert.join.noconditionaltask=true;
set hive.auto.convert.join.noconditionaltask.size=10000000;
set hive.mapjoin.smalltable.filesize=200000000;

set hive.merge.mapfiles = false;
set hive.merge.mapredfiles = false; --MR操作结束时,不合并小文件
set hive.merge.size.per.task = 256000000;
set hive.merge.smallfiles.avgsize = 256000000;
set hive.merge.orcfile.stripe.level=false;
set hive.merge.rcfile.block.level=false;

--指定tmp.tmp_01的文件存储格式,默认为textfile
set hive.default.fileformat = orc;

drop table if exists tmp.tmp_01;
create table tmp.tmp_01 
--STORED AS orc
as
SELECT
      a.item_sku_id 
FROM  (
            SELECT
                    item_sku_id,sku_name,brandname_cn,data_type
            FROM big_table 
            WHERE dt = '2022-02-15' AND brandname_cn = '汾酒'
            --distribute by rand(1) -- 不分组
      ) a --数据量远远大于10M
LEFT OUTER JOIN
      (     SELECT item_sku_id 
            FROM small_table 
            WHERE version = '1' AND normal_brandname_en = 'fenjiu' AND dt = '2022-02-15'
      ) b --数据量大小小于10M
ON a.item_sku_id = b.item_sku_id
WHERE b.item_sku_id IS NULL;

结果:

2022-02-17 16:53:18 INFO Table tmp.tmp_01 stats: [numFiles=18020, numRows=23, totalSize=887747, rawDataSize=2252]
2022-02-17 16:53:18 INFO MapReduce Jobs Launched:
2022-02-17 16:53:19 INFO Stage-4: Map: 18020   Cumulative CPU: 205038.93 sec   HDFS Read: 193.386 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 3m28s419ms job_8766029101801_36451400
2022-02-17 16:53:19 INFO 
2022-02-17 16:53:19 INFO Total MapReduce CPU Time Spent: 2d8h57m18s930ms
2022-02-17 16:53:19 INFO Total Map: 18020  Total Reduce: 0
2022-02-17 16:53:19 INFO Total HDFS Read: 193.386 GB  Written: 0.000 GB

结果分析:

执行mapjoin(在map端关联聚合),不合并小文件,每一个map对应一个输出文件。输出结果出现大量小文件。

执行mapjoin,不合并小文件,大表重分区

set hive.auto.convert.join=true;
set hive.auto.convert.join.noconditionaltask=true;
set hive.auto.convert.join.noconditionaltask.size=10000000;
set hive.mapjoin.smalltable.filesize=200000000;

set hive.merge.mapfiles = true;
set hive.merge.mapredfiles = false; --MR操作结束时,不合并小文件
set hive.merge.size.per.task = 256000000;
set hive.merge.smallfiles.avgsize = 256000000;
set hive.merge.orcfile.stripe.level=false;
set hive.merge.rcfile.block.level=false;

--指定tmp.tmp_01的文件存储格式,默认为textfile
set hive.default.fileformat = orc;

drop table if exists tmp.tmp_01;
create table tmp.tmp_01 
--STORED AS orc
as
SELECT
      a.item_sku_id 
FROM  (
            SELECT
                    item_sku_id,sku_name,brandname_cn,data_type
            FROM big_table 
            WHERE dt = '2022-02-15' AND brandname_cn = '汾酒'
            --distribute by rand(1) -- 大表分组
      ) a --数据量远远大于10M
LEFT OUTER JOIN
      (     SELECT item_sku_id 
            FROM small_table 
            WHERE version = '1' AND normal_brandname_en = 'fenjiu' AND dt = '2022-02-15'
      ) b --数据量大小小于10M
ON a.item_sku_id = b.item_sku_id
WHERE b.item_sku_id IS NULL;

结果:

2022-02-16 22:53:00 INFO Table tmp.tmp_01 stats: [numFiles=3, numRows=23, totalSize=958, rawDataSize=2235]
2022-02-16 22:53:00 INFO Stage-1: Map: 18024  Reduce: 1009   Cumulative CPU: 372613.35 sec   HDFS Read: 193.289 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 5m32s865ms job_5690061100801_32621522
2022-02-16 22:53:00 INFO Stage-10: Map: 924   Cumulative CPU: 5424.53 sec   HDFS Read: 0.008 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 41s846ms job_5690061100801_32621870
2022-02-16 22:53:00 INFO Stage-4: Map: 858   Cumulative CPU: 1374.95 sec   HDFS Read: 0.001 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 43s592ms job_5690061100801_32621913
2022-02-16 22:53:00 INFO Total MapReduce CPU Time Spent: 4d9h23m32s830ms
2022-02-16 22:53:00 INFO Total Map: 19806  Total Reduce: 1009
2022-02-16 22:53:00 INFO Total HDFS Read: 193.298 GB  Written: 0.000 GB

结果分析:

执行mapjoin(在map端关联聚合),不合并小文件,大表预先分组,触发MR,减少mapjoin阶段输出的map数量(即当前job执行完成产生的中间结果文件数量)。由于输入map tasks少了, 输出结果小文件也大大减少。

执行mapjoin,合并小文件

set hive.auto.convert.join=true;
set hive.auto.convert.join.noconditionaltask=true;
set hive.auto.convert.join.noconditionaltask.size=10000000;
set hive.mapjoin.smalltable.filesize=200000000;

set hive.merge.mapfiles = true;
set hive.merge.mapredfiles = true; --MR操作结束时,合并小文件
set hive.merge.size.per.task = 256000000;
set hive.merge.smallfiles.avgsize = 256000000;
set hive.merge.orcfile.stripe.level=false;
set hive.merge.rcfile.block.level=false;

--指定tmp.tmp_01的文件存储格式,默认为textfile
set hive.default.fileformat = orc;

drop table if exists tmp.tmp_01;
create table tmp.tmp_01 
--STORED AS orc
as
SELECT
      a.item_sku_id 
FROM  (
            SELECT
                    item_sku_id,sku_name,brandname_cn,data_type
            FROM big_table 
            WHERE dt = '2022-02-15' AND brandname_cn = '汾酒'
            --distribute by rand(1) -- 不分组,因为此时分组毫无意义,只会徒增任务开销
      ) a --数据量远远大于10M
LEFT OUTER JOIN
      (     SELECT item_sku_id 
            FROM small_table 
            WHERE version = '1' AND normal_brandname_en = 'fenjiu' AND dt = '2022-02-15'
      ) b --数据量大小小于10M
ON a.item_sku_id = b.item_sku_id
WHERE b.item_sku_id IS NULL;

结果:

2022-02-16 23:12:45 INFO Table tmp.tmp_01 stats: [numFiles=1, numRows=23, totalSize=426, rawDataSize=2235]
2022-02-16 23:12:45 INFO Stage-1: Map: 18024  Reduce: 1009   Cumulative CPU: 365693.05 sec   HDFS Read: 193.289 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 3m21s803ms job_5690061100801_32623163
2022-02-16 23:12:45 INFO Stage-10: Map: 918   Cumulative CPU: 5232.29 sec   HDFS Read: 0.008 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 40s544ms job_8766029101801_36250732
2022-02-16 23:12:45 INFO Stage-4: Map: 1   Cumulative CPU: 13.95 sec   HDFS Read: 0.000 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 43s762ms job_8766029101801_36250769
2022-02-16 23:12:45 INFO Total MapReduce CPU Time Spent: 4d7h2m19s290ms
2022-02-16 23:12:45 INFO Total Map: 18943  Total Reduce: 1009
2022-02-16 23:12:45 INFO Total HDFS Read: 193.297 GB  Written: 0.000 GB

结果分析:

执行mapjoin(在map端关联聚合),合并小文件。输出结果小文件数量同样也大大减少。

总结

mapjoin会在小表与大表join时的优化提升还是很明显的,但使用时有一些问题需要注意。
上例中执行mapjoin, 有18020个map,就对应输出18020个小文件(执行mapReduce会在大大减少输出的小文件数,测试集群默认最大的reduce数量1009个)。
因此就需要考虑后期小文件的合并,在大量小文件的场景下,需要考虑的处理方式是开启小文件合并或者大表重分区

hive中间过程(两个job之间)大量小文件的调优思路

不重分区,不合并小文件

set hive.auto.convert.join=true;
set hive.auto.convert.join.noconditionaltask=true;
set hive.auto.convert.join.noconditionaltask.size=10000000;
set hive.mapjoin.smalltable.filesize=200000000;

set hive.merge.mapfiles = false;
set hive.merge.mapredfiles = false; --MR操作结束时,不合并小文件
set hive.merge.size.per.task = 256000000;
set hive.merge.smallfiles.avgsize = 256000000;
set hive.merge.orcfile.stripe.level=false;
set hive.merge.rcfile.block.level=false;

WITH tmp as 
(
SELECT
      a.* 
FROM  (
            SELECT
                    item_sku_id,sku_name,brandname_cn,data_type
            FROM big_table 
            WHERE dt = '2022-02-15' AND brandname_cn = '汾酒'
            --distribute by rand(1) -- 不分组
      ) a --数据量远远大于10M
LEFT OUTER JOIN
      (     SELECT item_sku_id 
            FROM small_table 
            WHERE version = '1' AND normal_brandname_en = 'fenjiu' AND dt = '2022-02-15'
      ) b --数据量大小小于10M
ON a.item_sku_id = b.item_sku_id
WHERE b.item_sku_id IS NULL
)
create table tmp.tmp_01 
as
SELECT
c.item_sku_id
FROM tmp c
join small_table d
on c.item_sku_id=d.item_sku_id

结果:

2022-02-17 20:49:21 INFO Stage-8: Map: 18026   Cumulative CPU: 210204.23 sec   HDFS Read: 193.388 GB HDFS Write: 0.001 GB SUCCESS  Elapsed : 2m55s772ms job_5690061100801_32863650
2022-02-17 20:49:21 INFO Stage-6: Map: 472   Cumulative CPU: 3330.08 sec   HDFS Read: 0.334 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 50s42ms job_5690061100801_32865433
2022-02-17 20:49:21 INFO Total MapReduce CPU Time Spent: 2d11h18m54s310ms
2022-02-17 20:49:21 INFO Total Map: 18498  Total Reduce: 0
2022-02-17 20:49:21 INFO Total HDFS Read: 193.722 GB  Written: 0.001 GB

2022-02-17 20:49:22 INFO Time taken: 1045.892 seconds, Fetched: 46 row(s)
2022-02-17 20:49:23 INFO 任务结束! sql执行耗时 0 hour 17 mins 38 s

结果分析:

不重分区,不合并小文件的情况下用时1045秒

不重分区,合并小文件

set hive.auto.convert.join=true;
set hive.auto.convert.join.noconditionaltask=true;
set hive.auto.convert.join.noconditionaltask.size=10000000;
set hive.mapjoin.smalltable.filesize=200000000;

set hive.merge.mapfiles = true;
set hive.merge.mapredfiles = true; --MR操作结束时,合并小文件
set hive.merge.size.per.task = 256000000;
set hive.merge.smallfiles.avgsize = 256000000;
set hive.merge.orcfile.stripe.level=false;
set hive.merge.rcfile.block.level=false;

WITH tmp as 
(
SELECT
      a.* 
FROM  (
            SELECT
                    item_sku_id,sku_name,brandname_cn,data_type
            FROM big_table 
            WHERE dt = '2022-02-15' AND brandname_cn = '汾酒'
            --distribute by rand(1) -- 不分组
      ) a --数据量远远大于10M
LEFT OUTER JOIN
      (     SELECT item_sku_id 
            FROM small_table 
            WHERE version = '1' AND normal_brandname_en = 'fenjiu' AND dt = '2022-02-15'
      ) b --数据量大小小于10M
ON a.item_sku_id = b.item_sku_id
WHERE b.item_sku_id IS NULL
)
create table tmp.tmp_01 
as
SELECT
c.item_sku_id
FROM tmp c
join small_table d
on c.item_sku_id=d.item_sku_id

结果:

2022-02-17 20:45:25 INFO Stage-8: Map: 18026   Cumulative CPU: 214628.08 sec   HDFS Read: 193.388 GB HDFS Write: 0.001 GB SUCCESS  Elapsed : 3m41s147ms job_8766029101801_36477823
2022-02-17 20:45:25 INFO Stage-6: Map: 472   Cumulative CPU: 3995.4 sec   HDFS Read: 0.334 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 59s677ms job_5690061100801_32865009
2022-02-17 20:45:25 INFO Total MapReduce CPU Time Spent: 2d12h43m43s480ms
2022-02-17 20:45:25 INFO Total Map: 18498  Total Reduce: 0
2022-02-17 20:45:25 INFO Total HDFS Read: 193.722 GB  Written: 0.001 GB

2022-02-17 20:45:27 INFO Time taken: 1074.534 seconds, Fetched: 46 row(s)
2022-02-17 20:45:27 INFO 任务结束! sql执行耗时 0 hour 18 mins 10 s

结果分析:

不重分区,合并小文件的情况下用时1074秒

重分区,合并小文件

set hive.auto.convert.join=true;
set hive.auto.convert.join.noconditionaltask=true;
set hive.auto.convert.join.noconditionaltask.size=10000000;
set hive.mapjoin.smalltable.filesize=200000000;

set hive.merge.mapfiles = true;
set hive.merge.mapredfiles = true; --MR操作结束时,合并小文件
set hive.merge.size.per.task = 256000000;
set hive.merge.smallfiles.avgsize = 256000000;
set hive.merge.orcfile.stripe.level=false;
set hive.merge.rcfile.block.level=false;

WITH tmp as 
(
SELECT
      a.* 
FROM  (
            SELECT
                    item_sku_id,sku_name,brandname_cn,data_type
            FROM big_table 
            WHERE dt = '2022-02-15' AND brandname_cn = '汾酒'
            distribute by rand(1) -- 分组
      ) a --数据量远远大于10M
LEFT OUTER JOIN
      (     SELECT item_sku_id 
            FROM small_table 
            WHERE version = '1' AND normal_brandname_en = 'fenjiu' AND dt = '2022-02-15'
      ) b --数据量大小小于10M
ON a.item_sku_id = b.item_sku_id
WHERE b.item_sku_id IS NULL
)
create table tmp.tmp_01 
as
SELECT
c.item_sku_id
FROM tmp c
join small_table d
on c.item_sku_id=d.item_sku_id

结果:

2022-02-17 19:57:57 INFO Stage-1: Map: 18026  Reduce: 1009   Cumulative CPU: 362544.56 sec   HDFS Read: 193.290 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 4m55s871ms job_5690061100801_32857972
2022-02-17 19:57:57 INFO Stage-9: Map: 928   Cumulative CPU: 5520.28 sec   HDFS Read: 0.008 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 2m33s752ms job_5690061100801_32858541
2022-02-17 19:57:57 INFO Stage-7: Map: 472   Cumulative CPU: 3638.63 sec   HDFS Read: 0.334 GB HDFS Write: 0.000 GB SUCCESS  Elapsed : 1m42s589ms job_5690061100801_32858927
2022-02-17 19:57:57 INFO Total MapReduce CPU Time Spent: 4d7h15m3s470ms
2022-02-17 19:57:57 INFO Total Map: 19426  Total Reduce: 1009
2022-02-17 19:57:57 INFO Total HDFS Read: 193.634 GB  Written: 0.000 GB

2022-02-17 19:57:58 INFO Time taken: 690.782 seconds, Fetched: 46 row(s)
2022-02-17 19:57:58 INFO 任务结束! sql执行耗时 0 hour 11 mins 44 s

结果分析:

重分区,合并小文件的情况下用时690秒

总结

在hive任务中间结果产生大量小文件的情况下,合并小文件设置对中间结果几乎没有影响;
但触发大表重分区,减少mapjoin阶段的map数量,会大大减少计算任务的用时

其他调优方式

压缩文件的处理

对于输出结果为压缩文件形式存储的状况,要解决小文件问题。若是在map输入前合并,对输出的文件存储格式并无限制;可是若是使用输出合并,则必须配合SequenceFile来存储,不然没法进行合并。

如下是实例:

set hive.exec.compress.output=true;  --开启hive最终输出数据压缩功能
set mapred.output.compression.type=BLOCK;
set mapred.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec;

drop table if exists tmp.tmp_02;
create table tmp.tmp_02
STORED AS SEQUENCEFILE
AS 
select *
from tmp.tmp_01

使用HAR归档文件

Hadoop的归档文件格式也是解决小文件问题的方式之一,并且hive提供了原生支持。

set hive.archive.enabled= true;
set hive.archive.har.parentdir.settable= true;
set har.partfile.size=1099511627776;
ALTER TABLE tmp_01 tARCHIVE PARTITION(ds='2008-04-08', hr='12' );
ALTER TABLE tmp_01UNARCHIVE PARTITION(ds='2008-04-08', hr='12' );
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值