一、hive的常用参数
-- 设置名称
set mapred.job.name = "test";
-- 每个Map最大输入大小
set mapred.max.split.size = 300000000;
-- 每个Map最小输入大小
set mapred.min.split.size = 100000000;
-- 执行Map前进行小文件合并
set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
--是否自动转换为mapjoin
set hive.auto.convert.join = true;
set hive.mapjoin.smalltable.filesize = 25000000;
set hive.auto.convert.join.noconditionaltask = true;
set hive.auto.convert.join.noconditionaltask.size = 10000000;
-- 在Map-only的任务结束时合并小文件
set hive.merge.mapfiles = true;
-- 在Map-Reduce的任务结束时合并小文件
set hive.merge.mapredfiles = true;
-- join 倾斜
set hive.optimize.skewjoin=true;
set hive.skewjoin.key=100000;
-- goupby 数据倾斜
set hive.map.aggr=true;
set hive.groupby.mapaggr.checkinterval = 100000;
set hive.groupby.skewindata=true;
-- 合并文件的大小
set hive.merge.size.per.task = 300000000;
set mapred.reduce.tasks = 30;
-- 动态分区
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
-- 并行开启
set hive.exec.parallel=true;
set hive.exec.parallel.thread.number=8;
二、join参数解析
hive的join方式默认common join,但是common join 在大表join小表的时候速度很慢,而且容易发生数据倾斜,而,map join 就会优化了此方面的问题,大大加快了join速度和缓解了数据倾斜!
(一). map join 到底优化在哪里?
- 因为每个mapjoin都要执行一次map,需要读写一次数据,所以多个mapjoin就要做多次的数据读写,合并mapjoin后只用读写一次,自然能大大加快速度。但是执行map是内存大小是有限制的,在一次map里对多个小表做mapjoin就必须把多个小表都加入内存,为了防止内存溢出,所以加了hive.auto.convert.join.noconditionaltask.size参数来做限制。不过,这个值只是限制输入的表文件的大小,并不代表实际mapjoin时hashtable的大小。
- Hive的MapJoin,在Join 操作在 Map 阶段完成,如果需要的数据在 Map 的过程中可以访问到则不再需要Reduce。
小表关联一个超大表时,容易发生数据倾斜,可以用MapJoin把小表全部加载到内存在map端进行join,避免reducer处理。
(二).join 参数说明
- 如果是小表,自动选择Mapjoin:
set hive.auto.convert.join = true; # 默认为false
该参数为true时,Hive自动对左边的表统计量,如果是小表就加入内存,即对 小表使用Map join
- 小表的最大文件大小,默认为25000000,即25M
set hive.mapjoin.smalltable.filesize;
hive.mapjoin.smalltable.filesize=25000000
默认值是25mb
- map join做group by 操作时,可以使用多大的内存来存储数据,如果数据太大,则不会保存在内存里
set hive.mapjoin.followby.gby.localtask.max.memory.usage;
默认值:0.55
- 本地任务可以使用内存的百分比
set hive.mapjoin.localtask.max.memory.usage;
默认值: 0.90
- 是否将多个mapjoin合并为一个
set hive.auto.convert.join.noconditionaltask = true;
- 多个mapjoin转换为1个时,所有小表的文件大小总和的最大值
set hive.auto.convert.join.noconditionaltask.size = 10000000;
(三).mapjoin的注意事项
- 用作join的关联字段的字段类型最好要一致
原因:40万行的小表处理了好几个小时,正常情况下应该几秒钟就完成了。但是执行mapjoin 的local task时一直卡住,查了好久原因,结果原来是做join的关联字段的类型不一致,一边是int, 一边是string,hive解释计划里显示它们都会被转成double再来join。我把字段类型改为一致的,瞬间就快了。照理说就算转成double也不该这么慢,不知道是不是hive的bug。 - Mapjoin 不能使用与 outer join
(四).数据倾斜
- 根本原因
发生数据倾斜主要是因为在数据进行shuffle的阶段的时候,数据分配不均匀,导致map处理的数据量差异过大,从而在大量ruduce完成任务后,需要等待少量(1个)reduce完成才能继续执行,任务进度卡在了99%. - 导致的操作
- 表现
任务进度长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。因为其处理的数据量和其他reduce差异过大。单一reduce的记录数与平均记录数差异过大,通常可能达到3倍甚至更多。 最长时长远大于平均时长。 - 典型的业务场景
(1) 空值产生的数据倾斜
场景:经常有user_id缺失的情况,如果进行join操作,会导致数据倾斜。
解决方法1: user_id为空的不参与关联
(2) 不同数据类型关联产生数据倾斜
场景:用户表中user_id字段为int,log表中user_id字段既有string类型也有int类型。当按照user_id进行两个表的Join操作时,默认的Hash操作会按int型的id来进行分配,这样会导致所有string类型id的记录都分配到一个Reducer中。
解决方法:把数字类型转换成字符串类型