Hive优化

1 Hive性能优化方式

1.1 join性能优化介绍

img

从上图可以看出Reduce端join的性能最差,因为其要经过Shuffle阶段。

比其好上一些的在Map端join,如果性能还达不到要求则在Map端Join的基础之上将表分桶。

将分桶进行排序然后进行join操作

1.2 map端join和reduce端join区别

1.3 map端Join条件

  1. 大表和小表join,小表可以完全放入内存
  2. bucket表之间join

1.4 Sort Map Bucket 简称 SMB

首先进行打排序,然后合并,再放到相应的bucket中去。

  1. 需要在每个桶中按相同字段排序
  2. 打开设置, set hive.auto.convert.sortmerge.join=true;

1.5 查询性能优化

1.6 列式存储

Record Columnar File

  1. 更快地加载
  2. 更快速的查询
  3. 更高效的存储空间利用率

2 简介 实战

举个例子:比如男uv,女uv,像淘宝一天30亿的pv,如果按性别分组,分配2个reduce,每个reduce处理15亿数据。

面对这些问题的优化手段:

2.1 hive性能低下根源

RAC(Real Application Cluster)真正应用集群就像一辆机动灵活的小货车,响应快;

Hadoop就像吞吐量巨大的轮船,启动开销大,如果每次只做小数量的输入输出,利用率将会很低。

所以用好Hadoop的首要任务是增大每次任务所搭载的数据量。

Hadoop的核心能力是parition和sort,因而这也是优化的根本。

hadoop 处理数据的过程,显著特征:

最后得出的结论是:避实就虚,用 job 数的增加,输入量的增加,占用更多存储空间,充分利用空闲 CPU 等各种方法,分解数据倾斜造成的负担。

2.2 配置角度优化

  我们也可以从Hive的配置解读去优化。Hive系统内部已针对不同的查询预设定了优化方法,用户可以通过调整配置进行控制。

2.2.1 列裁剪

只读取查询中所需要的列,而忽略其它列。

select a,b from q where e < 10;

裁剪所对应的参数项为:hive.optimize.cp=true(默认值为真)

2.2.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.part=100;

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

3 join操作

3.1 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条件不同时

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);    

3.2 MAP JOIN操作

map 端join 条件:

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

INSERT OVERWRITE TABLE pv_users
    SELEST pv.pageid, u.age
    FROM page_view pv
        JOIN user u ON (pv.userid = u.userid)

mark

相关参数:

hive.join.emit.interval = 1000 
hive.mapjoin.size.key = 10000
hive.mapjoin.cache.numrows = 10000

3.3 GROUP BY 操作

进行GROUP BY操作时需要注意一下几点:

  不是所有的聚合操作都需要在reduce部分进行,很多聚合操作都可以先在Map端进行部分聚合,然后reduce端得出最终结果。

这里需要修改的参数为:

hive.map.aggr=true(用于设定是否在 map 端进行聚合,默认值为真)  
hive.groupby.mapaggr.checkinterval=100000(用于设定 map 端进行聚合操作的条目数)

4 合并小文件

我们知道文件数目小,容易在文件存储端造成瓶颈,给 HDFS 带来压力,影响处理效率。对此,可以通过合并Map和Reduce的结果文件来消除这样的影响。

合并小文件参数有:

是否合并Map输出文件:hive.merge.mapfiles=true(默认值为真)
是否合并Reduce端输出文件:hive.merge.mapredfiles=false(默认值为假)
合并文件的大小:hive.merge.size.per.task=256*1000*1000(默认值为 256000000)

5 优化常用手段

主要这三个属性决定:

hive.exec.reducers.bytes.per.reducer   #这个参数控制一个job会有多少个reducer来处理,依据的是输入文件的总大小。默认1GB。

hive.exec.reducers.max    #这个参数控制最大的reducer的数量, 如果 input / bytes per reduce > max  则会启动这个参数所指定的reduce个数。  这个并不会影响mapre.reduce.tasks参数的设置。默认的max是999。

mapred.reduce.tasks #这个参数如果指定了,hive就不会用它的estimation函数来自动计算reduce的个数,而是用这个参数来启动reducer。默认是-1。

参数设置的影响

  1. 如果reduce太少:如果数据量很大,会导致这个reduce异常的慢,从而导致这个任务不能结束,也有可能会OOM
  2. 如果reduce太多: 产生的小文件太多,合并起来代价太高,namenode的内存占用也会增大。如果我们不指定mapred.reduce.tasks, hive会自动计算需要多少个reducer。