最近在做hive sql优化相关的一些工作,一些经历与同事分享的同时,记录于此。
在优化过程中的一些总结,可能有的地方说法有待进一步验证,如下:
1 在union all子句里边最好不要有join,应该先union all之后再与其它表join,group by也是如此。
2 下面的情况除外:
union all之后的表,如果是要与一个超级大表join,那么需要想办法将此超级大表拆开,分别与union all的小表join后,再union all
比如:
select K.a,K.b,K.c
from
(select a,b,c from A1
union all
select a,b,c from A2
) k join B on k.a=B.a
group by a,b,c; //B是一个比A1和A2大很多的表
如果此语句执行速度很慢,且卡在reduce阶段,可考虑改为如下形式:
select K.a,K.b,K.c
from
(select a,b,c from A1 join B1 on A1.a=B1.a
union all
select a,b,c from A2 join B2 on A2.a=B2.a
) k group by a,b,c;
3 对于数据量大的多表join,可考虑增加mr任务的可用内存,set mapred.child.java.opts=-Xmx200m,默认200m,根据实际情况调节
4 尽量别把语句写的太长,用一些中间表,一个语句的job数不要太多,因为job切换也会耗时
5 合理的安排工作流中任务的执行顺序,尽可能充分的利用资源。
6 关于公共的子表是否需要独立出来执行
假设A B C D构成一个工作流,执行顺序为A-B-C|D,C与D是并发执行的关系
此时若C与D中有一个公共的子表,执行的时间是5分钟,而C与D执行分别需要10分钟。A执行需要10分钟,B执行需要5分钟,整个工作流完成需要25分钟。
将C与D的公共子表摘出来做为E,如果把E放在A中,那么A的时间将增加为15分钟,B依然5分钟,C与D最好情况5分钟完成,整个工作流依然是25分钟。
好在我们有B,可以把E放在与B并发执行,此时工作流时间为10+5+5=20。如果没有B的话,摘出来就意义不大。
因为摘出来的子表有一个写数据的过程,会增加io开销,如果不是公用价值很大,或者很复杂的语句,就没有必要了。
7 关于数据倾斜
在优化过程中,曾发现某个执行非常慢的任务,是卡在reduce阶段,持续99%很长时间,请同事在后台帮忙查了下,发现24个reduce任务,有两个才进行到60%,由此怀疑有数据倾斜的现象发生。据此,对那个sql中的几个相关表的join key,做了下统计,发现有一个表的某主键值跟其它值差距比较大,大概在10倍,千级与万级的区别。按说此差距也不至于倾斜的那么厉害,后来怀疑是因为join的过程,可能产生了更大的倾斜。对此问题没有直接解决,而是通过两个方式间接解决:
通过改写join语句,让参与join的表变小,如2描述
让有倾斜的表先不参与join,等其它都join完成,最后再join那个表
最终问题得以解决,不确定是哪一个起关键作用。
8 在distribute by中不要对字段用udf等函数,会使速度非常的慢,好的方式是先用udf对原表转换一遍,再用ditribute by