Hive调优及优化

一、数据倾斜

Hive 中数据倾斜的基本表现

  • 一般都发生在 Sql 中 group by 和 join on 上,而且和数据逻辑绑定比较深。
  • 任务进度长时间维持在99%(或100%),查看任务监控页面**,发现只有少量(1个或几个)reduce子任务未完成**。因为其处理的数据量和其他reduce差异过大

如何产生

  • key的分布不均匀或者说某些key太集中
  • 业务数据自身的特性,例如不同数据类型关联产生数据倾斜
  • SQL语句导致的数据倾斜

二、优化SQL语句导致的数据倾斜

 2.1 、空值引发的数据倾斜

第一种:可以直接不让null值参与join操作,即不让null值有shuffle阶段

create table res_tbl as  
select n.* from 
(select * from res where id is not null ) n 
left join org_tbl o on n.id = o.id;


第二种:因为null值参与shuffle时的hash结果是一样的,那么我们可以给null值随机赋值,这样它们的hash结果就不一样,就会进到不同的reduce中

SELECT *
FROM log a
 LEFT JOIN users b ON CASE 
   WHEN a.user_id IS NULL THEN concat('hive_', rand())
   ELSE a.user_id
  END = b.user_id;
  • join内连接,是返回两个表中都有的符合条件的行。
  • left   join左连接,是返回左表中所有的行及右表中符合条件的行。
  • right   join右连接,是返回右表中所有的行及左表中符合条件的行。
  • full   join全连接,是返回左表中所有的行及右表中所有的行,并按条件连接。

2.2 不同数据类型引发的数据倾斜

对于两个表join,表a中需要join的字段key为int,表b中key字段既有string类型也有int类型。当按照key进行两个表的join操作时,默认的Hash操作会按int型的id来进行分配,这样所有的string类型都被分配成同一个id,结果就是所有的string类型的字段进入到一个reduce中,引发数据倾斜。

解决方案

如果key字段既有string类型也有int类型,我们直接把int类型都转为string就好了,这样key字段都为string,hash时就按照string类型分配了

SELECT *
FROM users a
 LEFT JOIN logs b ON a.usr_id = CAST(b.user_id AS string);

2.3、 不可拆分大文件引发的数据倾斜

我们在对文件进行压缩时,为避免因不可拆分大文件而引发数据读取的倾斜,在数据压缩的时候可以采用bzip2和Zip等支持文件分割的压缩算法。

2.4、 表连接时引发的数据倾斜

2.4.1 build table(小表)前置

Hive在解析带join的SQL语句时,会默认将最后一个表作为probe table(探查表),将前面的表作为build table并试图将它们读进内存。如果表顺序写反,probe table在前面,引发OOM的风险就高了。

在维度建模数据仓库中,事实表就是probe table,维度表就是build table。假设现在要将日历记录事实表和记录项编码维度表来join 维度表在前,事实表在后

2.4.2 Reduce join 改为Map join

在Reduce阶段完成join。容易发生数据倾斜。可以用MapJoin把小表全部加载到内存在map            端进行join,避免reducer处理

  •  MapJoin set hive.auto.convert.join = true;默认为true 把小表自动加载到内存中
  •  hive.mapjoin.smalltable.filesize   默认值25000000(25MB) 即当小于25MB的时候默认是小表

三、聚合类group by操作,发生数据倾斜

3.1 map段部分聚合

  • 开启Map端聚合参数设置set hive.map.aggr=true
    默认 true,并不是所有的聚合操作都需要在reduce部分进行,很多聚合操作都可以先在Map端进行部分聚合,然后reduce端得出最终结果。
    对应的优化器为GroupByOptimizer
  • 在Map端进行聚合操作的条目数目set hive.grouby.mapaggr.checkinterval=100000
    hive.groupby.mapaggr.checkinterval设置map端预聚合的行数阈值,超过该值就会分拆job,默认值100000

3.2 、有数据倾斜的时候进行负载均衡(默认是false)

  • set hive.groupby.skewindata = true 

    hive.groupby.skewindatafalse, 解释:在group by时启动两个MR job。第一个job会将map端数据随机输入reducer,每个reducer做部分聚合,相同的key就会分布在不同的reducer中。第二个job再将前面预处理过的数据按key聚合并输出结果,这样就起到了均衡的效果。
  • 阶段拆分-两阶段聚合 需要聚合的key前加一个随机数的前后缀,这样就均匀了,之后再按照原始的key聚合一次

  • 生成的查询计划有两 个 MapReduce 任务。在第一个 MapReduce 中,map 的输出结果集合会随机分布到 reduce 中, 每个 reduce 做部分聚合操作,并输出结果。相同的 GroupB Key 有可能分发到不同的 reduce 中,从而达到负载均衡的目的;第二个 MapReduce 任务再根据预处 理的数据结果按照 Group By Key 分布到 reduce 中(这个过程可以保证相同的 Group By Key 分布到同一个 reduce 中),最后完成最终的聚合操作。

     假设 key = 水果
     select count(substr(a.tmp,1,2)) as key from(
     select concat(key,'_',cast(round(10*rand())+1 as string)) tmp
     from table group by tmp )a group by key

    四、Hive 小文件问题及解决

产生原因:

  • 动态分区插入数据,产生大量的小文件,从而导致map数量剧增;

  • 倒入数据时产生,每执行一次 insert 时hive中至少产生一个文件,文件数量=MapTask数量*分区数,insert 导入时至少会有一个MapTask

解决方案:

输入阶段合并

需要更改Hive的输入文件格式,即参数hive.input.format,默认值是org.apache.hadoop.hive.ql.io.HiveInputFormat,我们改成org.apache.hadoop.hive.ql.io.CombineHiveInputFormat。 这样比起上面调整mapper数时,又会多出两个参数,分别是mapred.min.split.size.per.nodemapred.min.split.size.per.rack,含义是单节点和单机架上的最小split大小。如果发现有split大小小于这两个值(默认都是100MB),则会进行合并


输出阶段合并

直接将hive.merge.mapfiles和hive.merge.mapredfiles都设为true即可,前者表示将map-only任务的输出合并,后者表示将map-reduce任务的输出合并。 另外,hive.merge.size.per.task可以指定每个task输出后合并文件大小的期望值,hive.merge.size.smallfiles.avgsize可以指定所有输出文件大小的均值阈值,默认值都是1GB。如果平均大小不足的话,就会另外启动一个任务来进行合并。

五、其他HiveSQL优化

5.1、 sort by代替order by

HiveSQL中的order by与其他SQL方言中的功能一样,就是将结果按某字段全局排序,这会导致所有map端数据都进入一个reducer中,在数据量大时可能会长时间计算不完。

如果使用sort by,那么还是会视情况启动多个reducer进行排序,并且保证每个reducer内局部有序。为了控制map端数据分配到reducer的key,往往还要配合distribute by一同使用。如果不加distribute by的话,map端数据就会随机分配到reducer。
举个例子,假如要以UID为key,以上传时间倒序、记录类型倒序输出记录数据。
 

select uid,upload_time,event_type,record_data
from calendar_record_log
where pt_date >= 20190201 and pt_date <= 20190224
distribute by uid
sort by upload_time desc,event_type desc;

5.2、 group by代替distinct 

当要统计某一列的去重数时,如果数据量很大,count(distinct)就会非常慢,原因与order by类似,count(distinct)逻辑只会有很少的reducer来处理。这时可以用group by来改写

select count(1) from (
	select uid from calendar_record_log
	where pt_date >= 20190101
	group by uid
) t;

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于Hive调优思路,可以从以下几个方面入手: 1. 数据存储和分区设计:合理的数据存储和分区设计可以提高查询性能。根据业务需求,将数据按照合适的列进行分区,这样可以减少数据扫描量。 2. 数据压缩:使用合适的压缩格式可以减小数据存储空间,并提高查询性能。例如,使用Snappy、LZO等压缩算法来减少磁盘IO和网络传输。 3. 数据倾斜处理:当某些列的值过于集中,导致某些Task处理的数据量远大于其他Task时,会导致任务执行时间不均衡。通过对倾斜键进行处理,如使用随机前缀或者进行拆分处理,可以解决数据倾斜问题。 4. 合理设置Hive参数:根据实际情况调整Hive的参数配置,以提高查询性能。常见的参数包括:hive.exec.parallel、hive.tez.container.size、hive.vectorized.execution.enabled等。 关于Hive的参数配置,下面是一些常用的参数: 1. hive.exec.parallel:设置并行执行任务的线程数,默认为1。可以根据集群资源情况适当调整,以提高任务执行效率。 2. hive.tez.container.size:设置每个Tez任务的容器大小,默认为1024(MB)。可以根据具体的任务需求和集群资源情况进行调整,以充分利用集群资源。 3. hive.vectorized.execution.enabled:启用向量化执行,可提高查询性能。默认为false,可以通过设置为true来开启向量化执行。 4. hive.optimize.sort.dynamic.partition:动态分区排序优化,默认为true。对于动态分区表,可以开启该参数以提高插入性能和查询性能。 5. hive.stats.autogather:自动收集统计信息,默认为true。开启该参数可以帮助优化查询计划,提高查询性能。 以上是一些常见的Hive调优思路和参数配置,具体的调优策略还需要根据实际情况进行调整和优化

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值