首先hive本质就是mapreduce,那么优化就从mapreduce开始入手。
然而mapreduce的执行快慢又和map和reduce的个数有关,所以我们先从这里下手,调整并发度。
关于map的优化:
1.调整block
作业会通过input的目录产生一个或者多个map任务。set dfs.block.size
因为没份数据都是block,而block的大小直接影响了split切分的分数,如果切分的更细一点,那么split个数会增加,那直接会影响map的增加,所以blocksize是直接影响并发度的因素
通过该配置参数来调整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;
还可以直接设置map个数:
set mapred.map.tasks=10;
注:这种方式进行设置,并不一定会生效
开启combiners
Map端聚合 hive.map.aggr=true
注:用的好了,可以提高性能,用的不好了,反而影响结果(可以参考mapreduce的combiner)
关于reduce的优化:
hive.exec.reducers.bytes.per.reducer;reduce任务处理的数据量
这个参数可以在提交sql的时候设置这个参数,这个参数可以直接设置一个数字,这个数字会直接影响reduce的个数
reduce个数的计算公式(hive.exec.reducers.bytes.per.reducer):
reduce个数 = InputFileSize / bytes pre reduce(整个数据的大小 / 每一个reduce可以处理的大小)
hive.exec.reducers.bytes.per.reducer这个参数设置的就是每个reduce可以处理的大小
set mapred.reduce.tasks=10(也是设置reduce的个数)
如果hive.exec.reducers.bytes.per.reducer和set mapred.reduce.tasks同时设置了,set mapred.reduce.tasks 优先级高
---------------------------------------------------------------------------------------------------------------------------------------------------------------
例如:1)查询count这种聚合函数,如果使用的group by的话会多个reduce来运行,而没有使用group by的话就是单个reduce来运行,所以面对大量数据做聚合,使用group by
where pt=‘20190308’ 单个reduce运行 (bed case)
where pt=‘20190308’ group by pt 多个reduce运行 (good case)
2)两张表做join的时候,使用on是多个reduce来运行,而不使用on则是一个reduce来运行(两张表做join,一定要用on)
select id,xxx from table_A A join table_B B on A.id=B.id 多个reduce运行 (good case)
select id,xxx from table_A A join table_B B where A.id=B.id 单个reduce运行 (bed case)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
partition做分区,直接定位到分区,省去一些不必要的过滤
分区的问题看上一篇博客
Map Join:类似一种检索配置的形式
/*+ MAPJOIN(tablelist) */,必须是小表,不要超过1G,或者50万条记录
有A,B两张表,A想joinB A.join(B)
如果A是小表,B是大表,可以将A放入内存(小表有多小?尽量不要超过1G)
Union操作:合并去重操作
table_A: A,B,C table_B:B,C,D Union:A,B,C,D
Union all操作:直接追加不做去重
table_A: A,B,C table_B:B,C,D Union:A,B,C,B,C,D
Union all不去重,性能明显高于Union
先做union all再做join或group by等操作可以有效减少mapreduce过程,尽管是多个Select,最终只有一个mapreduce
明确数据不相同或者有相同不需要去重就用Union all,有相同就用Union
Automatic merge:
执行hive的过程中,中间可能产生一些小文件,在中间做一些文件的合并
– hive.merge.mapfiles = true 是否和并 Map 输出文件,默认为 True
– hive.merge.mapredfiles = false 是否合并 Reduce 输出文件,默认为 False
– hive.merge.size.per.task = 256*1000*1000 合并文件的大小
Multi-Count Distinct:
当我们写一个sql的时候
sql(group by key)------>一个MR job
map相同的key------->同一个reduce
假设数据源存在数据倾斜问题
所有的reduce都完成了,最后等1个reduce
怎么优化?(mapreduce中:对key改写来解决此类问题)
hive中:set hive.groupby.skewindata=true (会自动的帮你完成负载均衡)
--------------------------------------------------------------------------------------------------------
在mapreduce中,什么时候会耗时比较严重呢?
在做join的时候会耗时比较严重
hive是可以支持多表链接的
一个mapreduce的例子:
select a.val, b.val, c.val from a join b on(a.key = b.key1) join c on(a.key = c.key1) 一个MR job(good case)
select a.val, b.val, c.val from a join b on(a.key = b.key1) join c on(b.key2 = c.key) 多个MR job (bad case)
如果join多张表,join的key是同一个的时候,会生成一MR job
Hive的 Join 优 化 — — 表连接顺序
hive会默认把左边的数据放入内存,右边的数据做类似流数据(最好每次写join的是,小标放左边,大表放右边)
A.join(B)
reducer会尝试把A表进行缓存,因为A在前面B在后面(它会把最后一张表前的所有表都尝试进行缓存)如果A完全可以放入内存中去,对B进行遍历,进行join,如果B有n条记录,那它的时间复杂度就是O(n)
如果A,B都不在内存中,A的大小是m,B的大小是n,那它的时间复杂度就是O(m*n)
当大小表的顺序有问题,又不想改写顺序:
SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1); a表被视为大表
SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a JOIN b ON a.key = b.key; MAPJION会把小表全部读入内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配,由于在map是进行了join操作,省去了reduce运行的效率也会高很多
-------------------
左连接时,左表中出现的JOIN字段都保留,右表没有连接上的都为空。
SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key) WHERE a.ds='2009-07-07' AND b.ds='2009-07-07'
执行顺序是,首先完成2表JOIN,然后再通过WHERE条件进行过滤,这样在JOIN过程中可能会输出大量结果,再对这些结果进行过滤,比较耗时。
SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key AND a.ds='2009-07-07' AND b.ds='2009-07-07')
可以进行优化,将WHERE条件放在ON后,在JOIN的过程中,就对不满足条件的记录进行了预先过滤。
Hive的优化 — — 并行执行
同步执行hive的多个阶段,hive在执行过程,将一个查询转化成一个或者多个阶段。某个特定的job可能包含众多的阶段,而这些阶段可能并非完全相互依赖的,也就是说可以并行执行的,这样可能使得整个job的执行时间缩短。
hive执行开启:set hive.exec.parallel=true
数据倾斜:
我们优化大部分的目标都是为了解决数据倾斜的问题
• 操作
• Join
• Group by
• Count Distinct
• 原因
• key分布不均导致的
• 人为的建表疏忽
• 业务数据特点
• 症状
• 任务进度长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成
• 查看未完成的子任务,可以看到本地读写数据量积累非常大,通常超过10GB可以认定为发生数据倾斜
• 倾斜度
• 平均记录数超过50w且最大记录数是超过平均记录数的4倍
• 最长时长比平均时长超过4分钟,且最大时长超过平均时长的2倍
• 万能方法
• hive.groupby.skewindata=true
Hive的优化 ------数据倾斜------大小表关联
• 原因
• Hive在进行join时,按照join的key进行分发,而在join左边的表的数据会首先读入内存
如果左边表的key相对分散,读入内存的数据会比较小,join任务执行会比较快;
如果左边的表key比较集中,而这张表的数据量很大,那么数据倾斜就会比较严重;
• 思路
• 将key相对分散,并且数据量小的表放在join的左边,这样可以有效减少内存溢出错误发生的几率
• 使用map join让小的维度表先进内存
• 方法
• Small_table join big_table
Hive的优化 ------数据倾斜------大大表关联
• 原因
• 日志中有一部分的userid是空或者是0的情况,导致在用user_id进行hash分桶的时候,会将日志中userid为0或者空的数据分到一起,导致了过大的斜率
• 思路
• 把空值的key变成一个字符串加上随机数,把倾斜的数据分到不同的reduce上,由于null值关联不上,处理后并不影响最终结果
Hive的优化 ------数据倾斜------聚合时存在大量特殊值
• 原因
• 做count distinct时,该字段存在大量值为NULL或空的记录
• 思路
• count distinct时,将值为空的情况单独处理,如果是计算count distinct,可以不用处理,直接过滤,在最后结果中加1
• 如果还有其他计算,需要进行group by,可以先将值为空的记录单独处理,再和其他计算结果进行union
• 方法
• select cast(count(distinct(user_id))+1 as bigint) as user_cnt from tab_a where user_id is not null and user_id <> ‘ ‘