Hive性能优化——配置角度

爱⌒轻易说出口 提交于 2020-04-06 02:20:48

我们可以从Hive的配置解读去优化。Hive系统内部已针对不同的查询预设定了优化方法,用户可以通过调整配置进行控制, 以下举例介绍部分优化的策略以及优化控制选项。

列裁剪

Hive在读取数据时,可以只读取查询所需要的列,而忽略其他的列。列如,若有以下查询:SELECT a,b FROM q WHERE e<10;在实施此查询时,q表有5列(a,b,c,d,e),Hive只读取查询逻辑中真实需要的3列a、b、e,而忽略c,d;这样做节省了读取开销,中间表存储开销和数据整合开销。裁剪所对应的参数项为:hive.optimize.cp=true(默认值为真)

分区裁剪

可以在查询过程中减少不必要的分区。列如,若有以下查询: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(默认值为真)。

JOIN操作

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

JOIN原则

在使用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
  • 在做OUTER JOIN时也一样

如果Join的条件不同,比如:

INSTER 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操作的数目是对应的,上述查询和以下查询是等价的*/

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

Map JOIN操作

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

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

可以在Map阶段完成Join,相关参数:

  • hive.join.emit.interval = 1000 (在发出join结果之前对join最右操作缓存多少行的设定) 
  • hive.mapjoin.size.key = 10000()
  • hive.mapjoin.cache.numrows = 10000()

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 中),最后完成最终的聚合操作。

合并小文件

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

  • hive.merge.mapfiles=true(是否合并Map输出文件,默认值为真)
  • hive.merge.mapredfiles=false(是否合并Reduce 端输出文件,默认值为假)
  • hive.merge.size.per.task=256000000(合并文件的大小,默认值为 256000000)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!