Hive优化

企业级调优

1 Fetch抓取

Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算。例如:SELECT * FROM employees;在这种情况下,Hive可以简单地读取employee对应的存储目录下的文件,然后输出查询结果到控制台。
在hive-default.xml.template文件中hive.fetch.task.conversion默认是more,老版本hive默认是minimal,该属性修改为more以后,在全局查找、字段查找、limit查找等都不走mapreduce。

<property>
    <name>hive.fetch.task.conversion</name>
    <value>more</value>
    <description>
      Expects one of [none, minimal, more].
      Some select queries can be converted to single FETCH task minimizing latency.
      Currently the query should be single sourced not having any subquery and should not have any aggregations or distincts (which incurs RS), lateral views and joins.
      0. none : disable hive.fetch.task.conversion
      1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
      2. more  : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
    </description>
  </property>

案例实操
1)把hive.fetch.task.conversion设置成none,然后执行查询语句,都会执行mapreduce程序。

hive (default)> set hive.fetch.task.conversion=none;
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;

2)把hive.fetch.task.conversion设置成more,然后执行查询语句,如下查询方式都不会执行mapreduce程序。

hive (default)> set hive.fetch.task.conversion=more;
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;

2 本地模式

大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过,有时Hive的输入数据量是非常小的。在这种情况下,为查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多。对于大多数这种情况,Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。

用户可以通过设置hive.exec.mode.local.auto的值为true,来让Hive在适当的时候自动启动这个优化,默认是false。

set hive.exec.mode.local.auto=true;  //开启本地mr
//设置local mr的最大输入数据量,当输入数据量小于这个值时采用local  mr的方式,默认为134217728,即128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
//设置local mr的最大输入文件个数,当输入文件个数小于这个值时采用local mr的方式,默认为4
set hive.exec.mode.local.auto.input.files.max=10;

案例实操
1)开启本地模式,并执行查询语句

hive (default)> set hive.exec.mode.local.auto=true; 
hive (default)> select * from emp cluster by deptno;
Time taken: 1.328 seconds, Fetched: 14 row(s)

2)关闭本地模式,并执行查询语句

hive (default)> set hive.exec.mode.local.auto=false; 
hive (default)> select * from emp cluster by deptno;
Time taken: 20.09 seconds, Fetched: 14 row(s)

3.order by全局排序 & sort by “局部有序”(分区内部排序)

(1).order by 会对输入做全局排序,因此只有一个reducer(多个reducer无法保证全局有序)
只有一个reducer,会导致当数据输入规模较大时,需要较长的计算时间,影响效率.
如果指定了hive.mapred.mode=strict(默认值是nonstrict),这时就必须指定limit来限制输出条数,
原因是:所有的数据都会在同一个reducer端进行,数据量大的情况下可能不能出结果,那么在这样的严格模式下,必须指定输出的条数。
(2).如果用sort by进行排序,并且设置mapred.reduce.tasks>1, 则sort by只保证每个reducer的输出有序,不保证全局有序。
每个reducer出来的数据是有序的,但是不能保证所有的数据是有序的,除非只有一个reducer
好处是:执行了局部排序之后可以为接下去的全局排序提高不少的效率(其实就是做一次归并排序就可以做到全局排序了)
相关拓展

hive的模式:
严格模式:严格模式下 限制3种查询,1.order by 必须使用limit  2.分区表查询必须加where 条件   3.限制笛卡尔积
非严格模式: 默认
hive语句执行顺序:
from ... where ... group by ...  select .... order by ... limit ...;
//首先找到表,然后条件,然后分组,选一些字段,排序,最后挑选前几条。
hive底层 mr
hive on spark: hive作为计算底层调用的是spark
spark on hive: hive作为数据源,spark进行计算

4.减少job数

原因:jobs数比较多的作业运行效率相对比较低,原因是map reduce作业初始化的时间是比较长的。
比如即使有几百行的表,如果多次关联多次汇总,产生十几个jobs,耗时很长。
sum,count,max,min等UDAF,不怕数据倾斜问题,hadoop在map端的汇总合并优化,使数据倾斜不成问题
相关拓展


hive自定义函数:
    (1)UDF(User-Defined-Function)
		一进一出
	(2)UDAF(User-Defined Aggregation Function)
		聚集函数,多进一出
		类似于:count/max/min
	(3)UDTF(User-Defined Table-Generating Functions)
		一进多出
		如lateral view explore()

5.合并小文件

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

6.取其所需,投其所好

6.1 列裁剪(只读取查询中所需要用到的列,而忽略其它列)

	例如:SELECT a,b FROM q WHERE e<10;

6.2 分区裁剪(查询的过程中减少不必要的分区,只读取查询中所需要用到的分区)

6.3 JOIN操作

将条目少的表/子查询放在 Join 操作符的左边。
原因是在 Join 操作的 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生 OOM(out of memory 内存溢出) 错误的几率

6.4 MAP JOIN操作

Join 操作在 Map 阶段完成,不再需要Reduce,前提条件是需要的数据在 Map 的过程中可以访问到
相关的参数为:
hive.join.emit.interval = 1000
hive.mapjoin.size.key = 10000
hive.mapjoin.cache.numrows = 10000

6.5 GROUP BY操作

进行GROUP BY操作时需要注意一下几点:
(1)Map端部分聚合
   事实上并不是所有的聚合操作都需要在reduce部分进行,很多聚合操作都可以先在Map端进行部分聚合,然后reduce端得出最终结果。
   这里需要修改的参数为:

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

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

7.数据倾斜问题

(a).无效ID在关联时的数据倾斜问题

日志中常会出现信息丢失,比如每日约为 20 亿的全网日志,其中的user_id为主键,在日志收集过程中会丢失,出现主键为 null 的情况,
如果取其中的 user_id 和 bmw_users 关联,就会碰到数据倾斜的问题,
原因:Hive 中,主键为 null 值的项会被当做相同的 Key 而分配进同一个计算 Map。
解决方法 1:user_id 为空的不参与关联,子查询过滤 null(WHERE a.user_id IS NULL)
解决方法 2:函数过滤 null(CASE WHEN a.user_id IS NULL THEN CONCAT(‘dp_hive’,RAND()) ELSE a.user_id END =b.user_id)

(b)不同数据类型关联产生的倾斜问题

s8 的日志中有 32 为字符串商品 id,也有数值商品 id,日志中类型是 string 的,但商品中的 数值 id 是 bigint 的
不同数据类型 id 的关联会产生数据倾斜问题
猜想问题的原因:是把 s8 的商品id(string) 转成数值id 做 hash 来分配 Reduce,所以字符串 id 的 s8 日志,都到一个 Reduce 上了
解决方法:把数据类型转换成字符串类型

Hive排序相关

(1).sort by排序
会产生多个reducer,每个reducer中的数据是有序的(但是并不是全局有序)
可以通过设置set mapred.reduce.tasks=2 来设置sort by时生成的reducer的个数.

(2).排序 distribute by
hive中的distribute by是控制在map端如何拆分数据给reduce端的。
hive会根据distribute by后面列,根据reduce的个数进行数据分发,默认是采用hash算法。
对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。

select *
from paixu
distribute by class
sort by class asc,chinese asc;

(3).排序 cluster by
等价于sort by + distribute by(两个排序的列必须完全一致).

(4).order by排序
只有一个reduce,做全局排序。

count(1)与count(*)效果相同
count(name): 如果数据为空  不计数
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值