Hive优化
1.1 join操作进行优化
join优化是个复杂的问题,可以从以下几点进行优化
1)小表前置
大小表在join的时候,应该将小表放在前面,Hive在解析带join的SQL语句时,会默认将最后一个表作为大表,将前面的表作为小表并试图将它们读进内存。如果表顺序写反,大表在前面,可能会引发OOM。
2)key值相同
多表join的时候尽量使用相同的key来关联,这样会将会将多个join合并为一个MR job来处理。
3)利用map side join
map join特别适合大小表join的情况。Hive会将大表和小表在map端直接完成join过程,消灭reduce,效率很高。Hive 0.8版本之前,需要加上map join的暗示,以显式启用map join特性,具体做法是在select语句后面增加/+mapjoin(需要广播的较小表)/。
map join的配置项是hive.auto.convert.join,默认值true;还可以控制map join启用的条件,hive.mapjoin.smalltable.filesize,当较小表大小小于该值就会启用map join,默认值25MB。
1.2 空值引起数据倾斜优化
对于空值或者无意义的值引发的数据倾斜,该怎么处理呢?
当一张表中的空值过多的时候,所有的空值都会由一个reduce执行。这时候就可以为每一个空值进行赋值,可以由一个指定的字符串+随机数的方式赋值。
1.3 如何调整mapper数?
mapper数量与输入文件的split数息息相关,可以通过设置相关参数来调整mapper数。
1)可以直接通过参数mapred.map.tasks(默认值2)来设定mapper数的期望值,但它不一定是最终mapper数;
2)输入文件的总大小为total_input_size。HDFS中,一个块的大小由参数dfs.block.size指定,默认值64MB或128MB。所以得出来的默认mapper数就是:
default_mapper_num = total_input_size / dfs.block.size,但是它也不一定是最终的mapper数;
3)设置参数mapred.min.split.size(默认值1B)和mapred.max.split.size(默认值64MB)分别用来指定split的最小和最大值。那么split大小和split数计算规则是:
split_size = MAX(mapred.min.split.size, MIN(mapred.max.split.size, dfs.block.size));
split_num = total_input_size / split_size。
4)最终得出mapper数:
mapper_num = MIN(split_num, MAX(default_mapper_num, mapred.map.tasks))。
其中可变的参数有:mapred.map.tasks、dfs.block.size(不会为了一个程序去修改,但是也算是一个可变参数)、mapred.min.split.size、mapred.max.split.size,通过调整他们来实现,mapper数的变化。
1.4 如何调整reducer数?
利用参数mapred.reduce.tasks可以直接设定reducer数量,不像mapper一样是期望值。如果不设这个参数的话,Hive就会自行推测,逻辑如下:
1)参数hive.exec.reducers.bytes.per.reducer用来设定每个reducer能够处理的最大数据量。
2)参数hive.exec.reducers.max用来设定每个job的最大reducer数量。
3)reducer数:
reducer_num = MIN(total_input_size / reducers.bytes.per.reducer, reducers.max)。
reducer数量决定了输出文件的数量。如果reducer数太多,会产生大量小文件,对HDFS造成压力。如果reducer数太少,每个reducer要处理很多数据,容易拖慢执行时间也有可能造成OOM。
1.5 什么时候又需要合并文件?如何合并小文件?
当有很多小文件的时候没需要合并小文件,可以在输入阶段合并,也可以在输出阶段合并。
1)输入阶段合并
要想文件自动合并,需要更改Hive的输入文件格式,通过参数hive.input.format来更改,默认值是org.apache.hadoop.hive.ql.io.HiveInputFormat,需要改成org.apache.hadoop.hive.ql.io.CombineHiveInputFormat。还需要设置mapred.min.split.size.per.node和mapred.min.split.size.per.rack这两个参数,他们的含义是单节点和单机架上的最小split大小。设置完后,如果发现有split大小小于这两个值(默认都是100MB),则会进行合并。
2)输出阶段合并
设置hive.merge.mapfiles为true可以将map-only任务的输出合并;
设置hive.merge.mapredfiles为true可以将map-reduce任务的输出合并。另外,设置hive.merge.size.smallfiles.avgsize可以指定所有输出文件大小的均值阈值,一旦低于这个阈值,就会启动一个任务来进行合并。