Hive性能优化:
hive分配map和reduce数量
m,r数据量,对效率影响较大,因为在启动和初始化阶段是很耗费时间和资源的。
(1)控制mapper的数据量
通常情况下,作业会通过input的目录产生一个或多个map任务,
主要决定的因素有:input的文件总个数,input的文件大小
Eg:
a) 假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(block为128M,6个128m的块和1个12m的块),从而产生7个map数
b) 假设input目录下有3个文件a,b,c,大小分别为10m,20m,130m,那么hadoop会分隔成4个块(10m,20m,128m,2m),从而产生4个map数
两种方式控制map数量:
通过合并小文件来实现
合并小文件参数属性:
(1)是否合并Map输出文件:hive.merge.mapfiles=true(默认值为真)
(2)是否合并Reduce 端输出文件:hive.merge.mapredfiles=false(默认值为假)
(3)合并文件的大小:hive.merge.size.per.task=25610001000(默认值为256000000)
通过控制上一个job的reduce数量来控制
(2)控制reducer的数据量
Reducer的个数极大的影响执行效率,不指定reducer个数的情况下,hive分配reducer个数基于以下:
[if !supportLists](1) [endif]参数1:hive.exec.reducers.bytes.per.reducer(默认为1G)
[if !supportLists](2) [endif]参数2 :hive.exec.reducers.max(默认为999)
计算reducer数的公式
N=min(参数2,总输入数据量/参数1)
或者直接指定reducer个数:setmapred.reduce.tasks=13; //但是效果不是很好
Reducer个数不是越多越好,同map一样,启动和初始化reduce也会消耗时间和资源;有多少个reduce就有多少个输出文件
Reduce数过多:生成很多小文件,如果这些小文件作为下一个任务的输入,则会出现小文件过多的问题
Reduce过少:影响执行效率
什么情况下只会有一个reduce:
很多时候会发现,任务重不管数据量有多大,不管有没有调整reduce的个数,任务重一直都只有一个reduce
(1) 数据量小于hive.exec.reducers.bytes.per.reducer参数值的情况外
(2) 没有group by的汇总
(3) 用了order by
2.关于join:
(1)将数据量少的表或者子查询放在join的左边,
原因:在join操作的reduce阶段,位于join左边的表的数据会被加载进内存,将数据量少的表放在左侧,可以有效减少内存溢出的概率
注:如果多个join操作,且每个表参与多个join的字段相同,则将所有的join合并到一个mapperd程序中
Eg:
//在一个mapre程序中执行join
SELECT a.val, b.val, c.val
FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
//在两个mapred程序中执行join
SELECT a.val, b.val, c.val
FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
Eg2中会在两个mapper中执行,是由于参与两次join的表b的key不一致
(2) Map join的关键在于join操作中的某个表的数据量很小,join操作在map中完成,不再需要reduce
Eg:
SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a join b on a.key = b.key
注:mapjoin无法执行a full/right outer join b 操作、
相关参数:
hive.join.emit.interval= 1000
hive.mapjoin.size.key= 10000
hive.mapjoin.cache.numrows = 10000
注:在进行join操作的条件过滤的时候,应该讲过滤条件放在on关键词里面,这样可以提高效率
原因:join操作是在where操作之前执行,所以在执行join时,where条件并不能起到减少join数据的作用
3.group by优化
Map端聚合,首先在map端进行初步的聚合,最后在reduce端得出最终结果。
相关参数:
(1) hive.map.aggr = true //是否在 Map 端进行聚合,默认为True
(2) hive.groupby.mapaggr.checkinterval
= 100000 //在 Map 端进行聚合操作的条目数目
数据倾斜的聚合优化,对数据进行聚合优化,可以进行参数设置:
hive.groupby.skewindata = true
当此项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照Group
By Key 分布到 Reduce 中(这个过程可以保证相同的 Group
By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
4. 如何调整map数量
通常有一下参数可以决定map的数量
set mapred.max.split.size=256000000; --决定每个map处理的最大的文件大小,单位为B
set mapred.min.split.size.per.node=1; --节点中可以处理的最小的文件大小
set mapred.min.split.size.per.rack=1; --机架中可以处理的最小的文件大小
没有办法直接控制map的数量,只能通过以上参数的设置来控制map的分配数量
set mapred.max.split.size=1024000000;
setmapred.min.split.size.per.node=1024000000;
setmapred.min.split.size.per.rack=1024000000;
可以简单的理解为集群对一个表分区下面的文件进行分发到各个节点,之后根据mapred.max.split.size确认要启动多少个map数,逻辑如下 a.假设有两个文件大小分别为(256M,280M)被分配到节点A,那么会启动两个map,剩余的文件大小为10MB和35MB因为每个大小都不足241MB会先做保留 b.根据参数set
mapred.min.split.size.per.node看剩余的大小情况并进行合并,如果值为1,表示a中每个剩余文件都会自己起一个map,这里会起两个,如果设置为大于45*1024*1024则会合并成一个块,并产生一个map 如果mapred.min.split.size.per.node为10*1024*1024,那么在这个节点上一共会有4个map,处理的大小为(245MB,245MB,10MB,10MB,10MB,10MB),余下9MB 如果mapred.min.split.size.per.node为45*1024*1024,那么会有三个map,处理的大小为(245MB,245MB,45MB) 实际中mapred.min.split.size.per.node无法准确地设置成45*1024*1024,会有剩余并保留带下一步进行判断处理 c. 对b中余出来的文件与其它节点余出来的文件根据mapred.min.split.size.per.rack大小进行判断是否合并,对再次余出来的文件独自产生一个map处理
重点:注意各参数的设置大小,不要冲突,否则会异常,大小顺序如下
mapred.max.split.size <= mapred.min.split.size.per.node
<= mapred.min.split.size.per.rack
调整reduce数量,不建议随意设置reduce参数,可能调整参数更好一点
set hive.exec.reducers.bytes.per.reducer=1073741824