优化:加快程序运行时间+无数据倾斜
数据倾斜的实质:key的分布不均匀
场景1:跑得慢
场景2:reduce执行到99%(或100%)卡住。查看任务界面,发现只有少量(1个或几个)reduce子任务未完成,因为其处理的数据量比其他reduce子任务处理的大。
技术&&数据:
1.尽量尽早的过滤数据,减少每个阶段的数据量,对于分区表要加分区,同时只选择需要使用到的字段
2.尽量原子化操作,尽量避免一个SQL包含复杂逻辑,可以使用中间表在上游并发处理复杂的逻辑
3.join操作,小表注意放在join的左边,否则会引起磁盘和内存的大量消耗
1).使用mapjoin
2).参数化调节:set hive.auto.convert.join=false; (默认为true:高版本的hive自动检测加载表数据量,超过一定数据,自动加载到内存中)
4.只有一个reduce的场景 : 1.没有group by的汇总。2.order by。3.笛卡儿积。
5.尽量避免动态分区:
动态分区需要设置的参数:set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
6.使子查询并行执行:set hive.exec.parallel=true;
7.reduce的优化:
1)减少reduce数量:小文件的处理:在map端合并数据,减少文件输出,相当于combiner:
hive.map.aggr=true (注:不适用于大表操作)
2)离散化数据:
(1)特例:NULL值 搞成随机数使其输入到不同的reduce中
(2) 参数化:hive.groupby.skewindata = true;
当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group ByKey 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce中),最后完成最终的聚合操作
8.特殊情况特殊处理:在业务逻辑优化效果的不大情况下,有些时候可以将倾斜的数据单独拿出来处理。最后union回去;NULL不需要时不参与关联,需要时搞成随机数离散化
9.不同数据类型关联产生数据倾斜,尽量转换成同种类型
10.count distinct优化
优化前:select count(distinct id) from m
优化后: select count(1) from (select distinct id from m) tmp;
select count(1) from (select id from m group by id) tmp;
11.大表join大表性能调优:通过设置输入数据块的大小增加map数量
场景:观察执行过程,看到只生成2个map和一个reduce,感觉有问题
查找原因: 1.分别count(1)两张表对应的数据文件,发现两个文件大概在140MB左右。
2.desc看了两张表的字段分别有20多个,10个字段。
分析:1.由于表字段数较少,且数据长度短,导致140多MB的文件已经能存储上千万行的数据。
2.问题根源:HDFS中dfs.block.size默认设置为128MB.而当前的数据文件都是140MB左右,mr按照配置只能将140MB的文件拆分成2份(2个MAP)
3.MAP数量不足,并导致行数不够,跑数缓慢。
解决方案:
1.默认dfs.block.size=128MB这个设置不能系统级变更,随意修改后患无穷,只能从session级修改。
2.在sessin中设置参数,如下:
set hive.auto.convert.join=false #关闭map join
set dfs.block.size=64000000 #手动设置block size为64MB
set mapred.reduce.tasks=10 #手动设置让Reduce生产10个并行处理
说明:设置参数后重跑任务,map数据升为9,reduce数量为10,并行度提高了N倍,同一个SQL从原来10min+跑不出又化成3min不到完成。
12.假设一个SQL任务:
Select count(1) from popt_tbaccountcopy_mes where pt = ‘2012-07-04’;
该任务的inputdir /group/p_sdo_data/p_sdo_data_etl/pt/popt_tbaccountcopy_mes/pt=2012-07-04
共有194个文件,其中很多是远远小于128m的小文件,总大小9G,正常执行会用194个map任务。
Map总共消耗的计算资源: SLOTS_MILLIS_MAPS= 623,020
我通过以下方法来在map执行前合并小文件,减少map数:
set mapred.max.split.size=100000000;
set mapred.min.split.size.per.node=100000000;
set mapred.min.split.size.per.rack=100000000;
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
再执行上面的语句,用了74个map任务,map消耗的计算资源:SLOTS_MILLIS_MAPS= 333,500
对于这个简单SQL任务,执行时间上可能差不多,但节省了一半的计算资源。
大概解释一下,100000000表示100M,
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
这个参数表示执行前进行小文件合并,
前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,
小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),
进行合并,最终生成了74个块。
————————————————
业务: