一、慎用常用内置的api
数据量大尽量避免使用 count(distinct) ,这会导致所有数据在一个 reduce 内去重,导致运行缓慢,使用 group by 来代替
二、合理调整 map 数 和 reduce 数
下面我们列举几个常见的场景来分别进行调优
场景1
一个文件128M(一个 block 块的大小),但只有两列,数据量为几千万行,但只会产生一个 MapReduce
解决方案:
代码语言:javascript复制--设置10个reduceset mapred.reduce.tasks=10;-- 随机拆分成10个文件create table a_1 asselect * from adistribute by rand(123);
使用随机分配 key 的方案,用10个 reduce 来处理,此时数据就会随机分配到10个文件中,形成一个新的临时表。
场景2
一个表有成百上千的小文件,但仅仅是对表进行简单的 count。由于一个文件就会产生一个 map 任务,启动 map 任务的时间远远大于处理数据的时间。
解决方案:
代码语言:javascript复制set mapred.max.split.size=134217728;set mapred.min.split.size.per.node=104857600;set mapred.min.split.size.per.rack=104857600;set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
意思是:大于128M,按128M来切分;大于100M,小于128M的,按100M来切分;小于100M的,合并
这样就会先合并小文件,然后再启动 MapReduce 了
场景3
任务 reduce 普遍运行缓慢,迟迟没有运行完,那么需要合理调整 reduce 数量
如果不调整,hive 会自动帮你确定 reduce 任务,规则如下
代码语言:javascript复制--参数1,每个reduce任务处理的数据量,默认为1000^3=1Ghive.exec.reducers.bytes.per.reducer--参数2,每个任务最大的reduce数,默认为999hive.exec.reducers.max
reduce 数量 = min(参数2,总输入数据量/参数1)
也就是每个 reduce 处理1个g数据
设置方式1:
调整每个reduce处理的数据量
代码语言:javascript复制hive.exec.reducers.bytes.per.reducer
设置方式2:
直接设置 reduce 数量
代码语言:javascript复制set mapred.reduce.tasks=15;
当然 reduce 也不是越多越好,reduce 太多可能会产生非常多的小文件,增加 namenode 压力,执行 MapReduce 任务也会产生很多的map任务
三、小文件合并优化
代码语言:javascript复制--设置map端输出进行合并,默认为true set hive.merge.mapfiles = true--设置reduce端输出进行合并,默认为false set hive.merge.mapredfiles = true--设置合并文件的大小 set hive.merge.size.per.task = 256*1000*1000--当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。set hive.merge.smallfiles.avgsize=16000000
四、注意sql编写
(1)列裁剪,需要的列才输出,尽量不写*
(2)分区裁剪,设置好分区,不需要的分区不要读
(3)能用一个 sql 写完,绝不用临时表
(4)hive 可以自动把 union all 优化成一个 jon,但尽量不要再 union all 中写 group by 和 join,可以做一个临时表。
五、数据倾斜
(1)检查 join 条件的数值类型是不是一样
(2)join 操作之空 key 过滤,导致空值全在一个reduce中,可以使用下面的sql来解决这类问题
代码语言:javascript复制SELECT * FROM log a LEFT OUTER JOIN bmw_users b ON CASE WHEN a.user_id IS NULL THEN CONCAT('dp_hive', RAND()) ELSE a.user_id END = b.user_id;
在 空的key上加随机数来解决
(3)join 操作之小表join大表,可以使用 mapjoin
代码语言:javascript复制set hive.auto.convert.join = true;默认为trueset hive.mapjoin.smalltable.filesize=25000000;
(4)使用 hive 自动的数据倾斜优化
代码语言:javascript复制set hive.groupby.skewindata = true
生成的查询计划会有两个MR Job。
第一个MR Job中,Map的输出结果结合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果。这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的。
第二个MR Job再根据预处理的数据结果按照Group By Key分布到reduce中,这个过程可以保证相同的key被分到同一个reduce中,最后完成最终的聚合操作。