尽量避免一个SQL包含复杂逻辑,可以使用中间表来完成复杂的逻辑。
尽量先where筛选后再join,减少每个阶段的数据量,对于分区表要加分区条件,只选择需要使用到的字段。
当对3个或者更多个表进行join连接时,如果每个on子句都使用相同的连接键的话,那么只会产生一个MapReduce job。
表连接时将大表放后头(即小表联大表,跟传统sql相反)。Hive假定查询中最后的一个表是大表。它会将其它表缓存起来,然后扫描最后那个表。
如果union all的部分个数大于2,或者每个union部分数据量大,应该拆成多个insert into 语句,实际测试过程中,执行时间能大幅提升。
order by : 对查询结果进行全局排序,消耗时间长。需要 set hive.mapred.mode=nostrict
sort by : 局部排序,并非全局有序,提高效率
order by 排序,只存在一个reduce,这样效率比较低。可以用sort by操作,通常结合distribute by使用做reduce分区键
一般情况下,Limit语句还是需要执行整个查询语句,然后再返回部分结果。
有一个配置属性可以开启,避免这种情况—对数据源进行抽样
hive.limit.optimize.enable=true — 开启对数据源进行采样的功能
hive.limit.row.max.size — 设置最小的采样容量
hive.limit.optimize.limit.file — 设置最大的采样样本数
缺点:有可能部分数据永远不会被处理到
在hive里经常遇见数据倾斜问题。表现为:任务进度长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。
因为单一reduce的处理的数据量和其他reduce差异过大。通常可能达到3倍甚至更多。
1)、key分布不均匀
2)、业务数据本身的特性
3)、建表时考虑不周
4)、某些SQL语句本身就有数据倾斜
关键词 | 情形 | 后果 |
---|---|---|
join | 其中一个表较小,但是key集中 | 分发到某一个或几个Reduce上的数据远高于平均值 |
join | 大表与大表,但是分桶的判断字段0值或空值过多 | 这些空值都由一个reduce处理,灰常慢 |
group by | group by 维度过小,某值的数量过多 | 处理某值的reduce灰常耗时 |
count distinct | 某特殊值过多 | 处理此特殊值reduce耗时 |
第一通过hive.groupby.skewindata=true
控制生成两个MR Job,第一个MR Job Map的输出结果随机分配到reduce做次预汇总,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;减少某些key值条数过多某些key条数过小造成的数据倾斜问题。
第二通过hive.map.aggr = true(默认为true)
在Map端做combiner,假如map各条数据基本上不一样, 聚合没什么意义,做combiner反而画蛇添足,hive里也考虑的比较周到通过参数hive.groupby.mapaggr.checkinterval = 100000 (默认)hive.map.aggr.hash.min.reduction=0.5(默认)
,预先取100000条数据聚合,如果聚合后的条数/100000>0.5,则不再聚合
大表Join大表时:
把空值的key变成一个字符串加上随机数,把倾斜的数据分到不同的reduce上,由于null值关联不上,处理后并不影响最终结果。
count distinct大量相同特殊值时:
count distinct时,将值为空的情况单独处理,如果是计算count distinct,可以不用处理,直接过滤,在最后结果中加1。如果还有其他计算,需要进行group by,可以先将值为空的记录单独处理,再和其他计算结果进行union。
group by维度过小时:
采用sum() group by的方式来替换count(distinct)完成计算。
特殊情况特殊处理:
在业务逻辑优化效果的不大情况下,有些时候是可以将倾斜的数据单独拿出来处理。最后union回去。
map个数的主要的决定因素有: input的文件总个数,input的文件大小,集群设置的文件块大小(默认128M,不可自定义)。
由三个配置决定,
mapred.min.split.size.per.node 一个节点上split的至少的大小
mapred.min.split.size.per.rack 一个交换机下split至少的大小
mapred.max.split.size 一个split最大的大小
例如,若有大量小文件(小于128M),会产生多个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; -- 执行前进行小文件合并
前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的)进行合并
同理,增加map数也做相应设置
reduce数量由以下三个参数决定:
mapred.reduce.tasks 强制指定reduce的任务数量
hive.exec.reducers.bytes.per.reducer 每个reduce任务处理的数据量,默认为1000^3=1G
hive.exec.reducers.max 每个任务最大的reduce数,默认为999
一般根据输入文件的总大小,用它的estimation函数来自动计算reduce的个数:计算reducer数的公式很简单N=min( hive.exec.reducers.max ,总输入数据量/ hive.exec.reducers.bytes.per.reducer )
PS:这一块的优化,个人没什么经验。目前遇到的优化问题,主要还是集中在前两点上。
1、https://www.cnblogs.com/sandbank/p/6408762.html
2、https://www.cnblogs.com/xd502djj/p/3799432.html