1、空值null引起的数据倾斜
解决方案1:where条件过滤掉空值
解决方案2:关联时使用concat('hive',rand())给定随机值,因为null值参与shuffle时的hash结果是一样的,那么我们可以给null值随机赋值,这样它们的hash结果就不一样,就会进入到不同的reduce当中去。
2、不同的数据类型引发的数据倾斜
解决方案:用cast转换成相同的数据类型
3、不可拆分的大文件引发的数据倾斜
解决方案:将使用GZIP压缩等不支持文件分割的文件转为bzip和zip等支持文件分割的压缩方式。
4、数据膨胀引发的数据倾斜
解决方案:在HIVE中通过参数hive.new.job.grouping.set.cardinality配置的方式自动控制作业的拆解,该参数的默认值是30。表示针对grouping sets/rollups/cubes这类多维聚合的操作,如果最好拆解的键组合大于该值,会启用新的任务去处理大于该值之外的组合。如果在处理数据时,某个分组聚合的列有较大的倾斜,可以适当调小该值。
5、表关联引发的数据倾斜
解决方案:通常是将倾斜的数据存到分布式缓存中,分发到各个Map任务所在节点。在Map阶段完成Join操作,即Mapjoin,这避免了Shuffle,从而避免了数据倾斜。
MapJoin是HIVE的一种优化操作,其适用于小表Join大表的场景,由于表的Join操作是在map端且在内存进行的,所以其并不需要启动Reduce任务也不需要经过Shuffle阶段,从而能在一定程度上节省资源,提高Join效率。
hive.auto.convert.join=true; 默认值是true,自动开启Mapjoin优化。
hive.mapjoin.smalltable.filesize=2500000; 默认值是2500000(25M),通过该配置该属性来确定使用该优化的表的大小,如果表的大小小于此值就会被加载到内存中。
**注意**:使用默认启动该优化的方式如果出现莫名其妙的BUG(比如MAPJOIN并不起作用),就将以下两个属性置为fase手动使用MAPJOIN标记来启动该优化:
`hive.auto.convert.join=false` (关闭自动MAPJOIN转换操作)
`hive.ignore.mapjoin.hint=false` (不忽略MAPJOIN标记)
再提一句:将表放到Map端内存时,如果节点的内存很大,但还是出现内存溢出的情况,我们可以通过这个参数 `mapreduce.map.memory.mb` 调节Map端内存的大小。
6、确实无法减少数据量引发的数据倾斜
解决方案:这类问题最直接的方式就是调整reduce所执行的内存大小。
调整reduce的内存大小使用`mapreduce.reduce.memory.mb`这个配置。