1、map
通常情况下,作业会通过input的目录产生一个或者多个map任务。 主要的决定因素有: input的文件总个数,input的文件大小; 假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数; 假设input目录下有3个文件a,b,c,大小分别为10m,20m,130m,那么hadoop会分隔成4个块(10m,20m,128m,2m),从而产生4个map数; 即,如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块。 map数不是越多越好,也不是接近128M就可以了; ## 减少map数: 通过以下方法来在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; ## 增加map数: 当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。 其实一般情况下,map数是不用调的;
2、reduce
设置reduce数量:
set hive.exec.reducers.bytes.per.reducer=<number> #优先级小 如:<number> = 1024 1K一个reduce 如果大于<number>,就会多生成一个reduce set hive.exec.reducers.max=<number> #优先级中 set hive.exec.reducers.max=10; set mapreduce.job.reduces=<number> #优先级大 set mapreduce.job.reduces=15 对当前窗口,或者执行任务(脚本)过程中生效;
3、只会有一个reduce的情况:
以下情况设置了reduce的数量,也不会生效,还是只有一个; ## 没有group by ## order by ## 笛卡尔积:join的时候不加on条件或者无效的on条件,Hive只能使用1个reducer来完成笛卡尔积
4、map join
1,什么是MapJoin? MapJoin顾名思义,就是在Map阶段进行表之间的连接。而不需要进入到Reduce阶段才进行连接。这样就节省了在Shuffle阶段时要进行的大量数据传输。 从而起到了优化作业的作用。 2,MapJoin的原理: 通常情况下,要连接的各个表里面的数据会分布在不同的Map中进行处理。即同一个Key对应的Value可能存在不同的Map中。这样就必须等到Reduce中去连接。 要使MapJoin能够顺利进行,那就必须满足这样的条件:除了一份表的数据分布在不同的Map中外,其他连接的表的数据必须在每个Map中有完整的拷贝。 3,MapJoin适用的场景: 通过上面分析你会发现,并不是所有的场景都适合用MapJoin. 它通常会用在如下的一些情景:在两个要连接的表中,有一个很大,有一个很小,这个小表可以 存放在内存中而不影响性能,小表,不要超过1G,或者50万条记录。 这样我们就把小表文件复制到每一个Map任务的本地,再让Map把文件读到内存中待用。 4,MapJoin的实现方法: 1)在Map-Reduce的驱动程序中使用静态方法DistributedCache.addCacheFile()增加要拷贝的小表文件,。JobTracker在作业启动之前会获取这个URI列表, 并将相应的文件拷贝到各个TaskTracker的本地磁盘上。 2)在Map类的setup方法中使用DistributedCache.getLocalCacheFiles()方法获取文件目录,并使用标准的文件读写API读取相应的文件。 5,Hive内置提供的优化机制之一就包括MapJoin。 在Hive v0.7之前,需要使用hint提示 /*+ mapjoin(table1) */才会执行MapJoin 。Hive v0.7之后的版本已经不需要给出MapJoin的指示就进行优化。 它是通过如下配置参数来控制的,(此处的table1就是小表): hive> set hive.auto.convert.join=true; Hive还提供另外一个参数--表文件的大小作为开启和关闭MapJoin的阈值。 hive.mapjoin.smalltable.filesize=25000000 即25M
5、union all/distinct
union all / distinct == union union all / distinct 性能大于 union
6、数据倾斜
数据倾斜的操作: join group by count distinct 原因:key分布不均匀; 人为的建表疏忽; 业务数据特点。 症状:任务进度长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成; 查看未完成的子任务,可以看到本地读写数据量积累非常大,通常超过10GB可以认定为发生数据倾斜。 倾斜度:平均记录数超过50w且最大记录数是超过平均记录数的4倍;最长时长比平均时长超过4分钟,且最大时长超过平均时长的2倍。 ------------------------------------------------------------------------------ 万能方法: set hive.groupby.skewindata=true • 当选项设置为true:会生成两个MR job。 • 第一个MR job中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果, 这样处理的结果是相同的Group By Key有可能被分到不同的Reduce中,从而达到负载均衡的目的; • 第二个MR job再根据预处理的数据结果按照Group By Key分布到Reduce中(这个过程可以保证相同的 Group By Key 被分配到相同的reduce中),最终完成聚合的操作。 ------------------------------------------------------------------------------ 大 小 表 关 联: 原因: • Hive在进行join时,按照join的key进行分发,而在join左边的表的数据会首先读入内存,如果左边表的key相对分 散,读入内存的数据会比较小,join任务执行会比较快;而如果左边的表key比较集中,而这张表的数据量很大, 那么数据倾斜就会比较严重,而如果这张表是小表,则还是应该把这张表放在join左边; 思路: • 将key相对分散,并且数据量小的表放在join的左边,这样可以有效减少内存溢出错误发生的几率 • 使用map join让小的维度表先进内存。 方法: • Small_table join big_table ------------------------------------------------------------------------------ 大 大 表 关 联: 原因: • 日志中有一部分的userid是空或者是0的情况,导致在用user_id进行hash分桶的时候,会将日志中userid为0或者空的数据分到一起,导致了过大的斜率。 思路: • 把空值的key变成一个字符串加上随机数,把倾斜的数据分到不同的reduce上,由于null值关联不上,处理后并不影响最终结果; on case when (x.uid = '-' or x.uid = '0‘ or x.uid is null) then concat(‘-',rand()) else x.uid end =f.user_id; 如: select '${date}' as thedate, a.search_type, a.query, from table1 a left outer join table2 f on f.pt='${date}000000' and case when a.new_brand_id is null then concat('hive',rand() ) else a.new_brand_id end = f.brand_id; ------------------------------------------------------------------------------ 数据倾斜时怎么定位是由哪些数据引发的: 一般来说,我们只需要知道发生了数据倾斜即可,因为通用的解决数据倾斜问题的办法都不是针对特定值的处理来解决的(当然偶尔也有,比如null空值问题), 所以不关心到底具体到哪种值的数据导致了数据倾斜。当然,如果一定要知道,可以自己写个通用mr(就是wordcount,加combiner,输入可以指定特定字段组合 作为你的key,以及一个阈值,超过这个阈值的写出来,就可以知道哪些数据是非常多的) 2. 重新设计key问题 本身这种说法就只是阐述了一种思想,并没有给出具体方法。不过他的本意就是重新设计key的目的在于离散key值,去倾斜。在wordcount中,你可以把1个mr就完成 的事情分成2个去做,第一个就是在map过程中,在key后面随机打上一个标记值(这个值范围不要太大,和你reduce数目一致最好),然后做累加输出结果。然后第 一个mr的输出作为第二个mr的输入,在第二个mr的map中去掉标记值,再做一次累加即可。 ------------------------------------------------------------------------------ 聚 合 时 存 在 大 量 特 殊 值: 原因: • 做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 <>"