hive的优化
1.数据量较大的情况下慎用count(distinct name)
问题:使用disticnt函数,所有的数据只会shuffle到一个reducer上,导致reducer数据倾斜严重易造成数据倾斜,
比如:男UV,女UV,淘宝一天30亿的PV,如果按性别分组,分配2个reduce,每个reduce处理15亿数据。
优化:建议使用group by 字段,分组之后再对该字段做次数统计;
hive去重有几种方法?distinct 、 group by
2.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
好处是:执行了局部排序之后可以为接下去的全局排序提高不少的效率(其实就是做一次归并排序就可以做到全局排序了)
3.减少job数
原因:jobs数比较多的作业运行效率相对比较低,原因是map reduce作业初始化的时间是比较长的。
比如即使有几百行的表,如果多次关联多次汇总,产生十几个jobs,耗时很长。
***sum,count,max,min等UDAF,不怕数据倾斜问题,hadoop在map端的汇总合并优化,使数据倾斜不成问题
4.合并小文件
对小文件进行合并,是行至有效的提高调度效率的方法。
我们知道文件数目小,容易在文件存储端造成瓶颈,给 HDFS 带来压力,影响处理效率。
对此,可以通过合并Map和Reduce的结果文件来消除这样的影响。
用于设置合并属性的参数有:
是否合并Map输出文件:hive.merge.mapfiles=true(默认值为真)
是否合并Reduce端输出文件:hive.merge.mapredfiles=false(默认值为假)
合并文件的大小:hive.merge.size.per.task=25610001000(默认值为 256000000)
5.取其所需,投其所好
- 5.1 列裁剪(只读取查询中所需要用到的列,而忽略其它列)
例如:SELECT a,b FROM q WHERE e<10; - 5.2 分区裁剪(查询的过程中减少不必要的分区,只读取查询中所需要用到的分区)
- 5.3 JOIN操作
将条目少的表/子查询放在 Join 操作符的左边。
原因是在 Join 操作的 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生 OOM(out of memory 内存溢出) 错误的几率 - 5.4 MAP JOIN操作
Join 操作在 Map 阶段完成,不再需要Reduce,前提条件是需要的数据在 Map 的过程中可以访问到
相关的参数为:
hive.join.emit.interval = 1000
hive.mapjoin.size.key = 10000
hive.mapjoin.cache.numrows = 10000
- 5.3 JOIN操作
- 5.5 GROUP BY操作
进行GROUP BY操作时需要注意一下几点:
(1)Map端部分聚合
事实上并不是所有的聚合操作都需要在reduce部分进行,很多聚合操作都可以先在Map端进行部分聚合,然后reduce端得出最终结果。
这里需要修改的参数为:
hive.map.aggr=true(用于设定是否在 map 端进行聚合,默认值为真)
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 中),最后完成最终的聚合操作。
6.数据倾斜问题
- (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,做全局排序。