HiveQL优化

本文总结了HiveQL查询优化的关键策略,包括列裁剪、分区裁剪、JOIN操作优化、MAPJOIN、GROUPBY优化及小文件合并,旨在提高查询效率并解决数据倾斜问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HiveQL优化


根据网上的资料,简单的总结了一些HQL的优化方案。



1.列裁剪

Hive在读数据的时候,可以只读取查询中所需要用到的列,而忽略了其他列,例如,若有以下查询:

SELECT name,age FROM stu WHERE grade = '一年级'

在实施此项查询中,stu表有5列(name,age,gender,num,grade),Hive只读取查询逻辑中真正需要的三列name,age,grade 而忽略其他两列,这样做接生了读取开销,中间表存储开销和数据整合开销。
裁剪所对应的参数项为:hive.optimlze.cp=true(默认为真)

2.分区裁剪

可以在查询的过程中减少不必要的分区。 例如,若有以下查询:

SELECT * FROM (SELECT a1,COUNT(1) FROM T GROUP BY a1) subq WHERE subq.prtn=100; #(多余分区) 
SELECT * FROM T1 JOIN (SELECT * FROM T2) subq ON (T1.a1=subq.a2) WHERE subq.prtn=100;

查询语句若将“subq.prtn=100”条件放入子查询中更为高效,可以减少读入的分区 数目。 Hive 自动执行这种裁剪优化。  分区参数为:hive.optimize.pruner=true(默认值为真)

3.JOIN操作

在编写带有 join 操作的代码语句时,应该将条目少的表/子查询放在 Join 操作符的左边。 因为在 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,载入条目较少的表 可以有效减少 OOM(out of memory)即内存溢出。所以对于同一个 key 来说,对应的 value 值小的放前,大的放后,这便是“小表放前”原则。 若一条语句中有多个 Join,依据 Join 的条件相同与否,有不同的处理方法。

3.1JOIN原则

在使用写有 Join 操作的查询语句时有一条原则:应该将条目少的表/子查询放在 Join 操作符的左边。原因是在 Join 操作的 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生 OOM 错误的几率。对于一条语句中有多个 Join 的情况,如果 Join 的条件相同,比如查询:

INSERT OVERWRITE TABLE pv_users 
 SELECT pv.pageid, u.age FROM page_view p 
 JOIN user u ON (pv.userid = u.userid) 
 JOIN newuser x ON (u.userid = x.userid);  

如果 Join 的 key 相同,不管有多少个表,都会则会合并为一个 Map-Reduce
一个 Map-Reduce 任务,而不是 ‘n’ 个
在做 OUTER JOIN 的时候也是一样  
如果 Join 的条件不相同,比如:

INSERT OVERWRITE TABLE pv_users 
   SELECT pv.pageid, u.age FROM page_view p 
   JOIN user u ON (pv.userid = u.userid) 
   JOIN newuser x on (u.age = x.age);   

Map-Reduce 的任务数目和 Join 操作的数目是对应的,上述查询和以下查询是等价的:

INSERT OVERWRITE TABLE tmptable 
   SELECT * FROM page_view p JOIN user u 
   ON (pv.userid = u.userid);
 INSERT OVERWRITE TABLE pv_users 
   SELECT x.pageid, x.age FROM tmptable x 
   JOIN newuser y ON (x.age = y.age);    

4.MAP JOIN操作

Join 操作在 Map 阶段完成,不再需要Reduce,前提条件是需要的数据在 Map 的过程中可以访问到。比如查询:

INSERT OVERWRITE TABLE pv_users 
   SELECT /*+ MAPJOIN(pv) */ pv.pageid, u.age 
   FROM page_view pv 
  JOIN user u ON (pv.userid = u.userid);    

相关的参数为:
hive.join.emit.interval = 1000
hive.mapjoin.size.key = 10000
hive.mapjoin.cache.numrows = 10000
###GROUP BY操作

进行GROUP BY操作时需要注意一下几点:
Map端部分聚合  
事实上并不是所有的聚合操作都需要在reduce部分进行,很多聚合操作都可以先在Map端进行部分聚合,然后reduce端得出最终结果。  
这里需要修改的参数为: hive.map.aggr=true(用于设定是否在 map 端进行聚合,默认值为真) hive.groupby.mapaggr.checkinterval=100000(用于设定 map 端进行聚合操作的条目数)
有数据倾斜时进行负载均衡
此处需要设定 hive.groupby.skewindata,当选项设定为 true 是,生成的查询计划有两 个 MapReduce 任务。在第一个 MapReduce 中,map 的输出结果集合会随机分布到 reduce 中, 每个 reduce 做部分聚合操作,并输出结果。这样处理的结果是,相同的 Group By Key 有可 能分发到不同的 reduce 中,从而达到负载均衡的目的;第二个 MapReduce 任务再根据预处 理的数据结果按照 Group By Key 分布到 reduce 中(这个过程可以保证相同的 Group By Key 分布到同一个 reduce 中),最后完成最终的聚合操作。

5.合并小文件

我们知道文件数目小,容易在文件存储端造成瓶颈,给 HDFS 带来压力,影响处理效率。对此,可以通过合并Map和Reduce的结果文件来消除这样的影响。  
用于设置合并属性的参数有:是
否合并Map输出文件:hive.merge.mapfiles=true(默认值为真)
是否合并Reduce 端输出文件:hive.merge.mapredfiles=false(默认值为假)
合并文件的大小:hive.merge.size.per.task=25610001000(默认值为 256000000)

6.无效ID在关联时的数据倾斜问题

日志中常会出现信息丢失,比如每日约为 20 亿的全网日志,其中的 user_id 为主 键,在日志收集过程中会丢失,出现主键为 null 的情况,如果取其中的 user_id 和 bmw_users 关联,就会碰到数据倾斜的问题。原因是 Hive 中,主键为 null 值的项会被当做相同的 Key 而分配进同一个计算 Map。 解决方法 1:user_id 为空的不参与关联,子查询过滤 null

SELECT * FROM log a 
JOIN bmw_users b ON a.user_id IS NOT NULL AND a.user_id=b.user_id 
UNION All SELECT * FROM log a WHERE a.user_id IS NULL

解决方法 2 如下所示:函数过滤 null

SELECT * FROM log a LEFT OUTER 
JOIN bmw_users b ON 
CASE WHEN a.user_id IS NULL THEN CONCAT(‘dp_hive’,RAND()) ELSE a.user_id END =b.user_id;

调优结果:原先由于数据倾斜导致运行时长超过 1 小时,解决方法 1 运行每日平均时长 25 分钟,解决方法 2 运行的每日平均时长在 20 分钟左右。优化效果很明显。  
我们在工作中总结出:解决方法2比解决方法1效果更好,不但IO少了,而且作业数也少了。解决方法1中log读取两次,job 数为2。解决方法2中 job 数是1。这个优化适合无效 id(比如-99、 ‘’,null 等)产生的倾斜问题。把空值的 key 变成一个字符串加上随机数,就能把倾斜的 数据分到不同的Reduce上,从而解决数据倾斜问题。因为空值不参与关联,即使分到不同 的 Reduce 上,也不会影响最终的结果。附上 Hadoop 通用关联的实现方法是:关联通过二次排序实现的,关联的列为 partion key,关联的列和表的 tag 组成排序的 group key,根据 pariton key分配Reduce。同一Reduce内根据group key排序。

本文均总结自他人博客,发表仅方便自己或其他人使用,谢谢!
转载自:https://www.cnblogs.com/smartloli/p/4356660.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值