1.是参数优化
A .把 hive.fetch.task.conversion 设置成 more,然后执行查询语句的时候就不会走mr,不走mr的话执行效率会提高很多的。比如说select*from表,或者select *from表limit=5等等
B .数据量非常小的情况下我们可以让他走本地模式,set hive.exec.mode.local.auto=true;
这样的话可以让通过本地模式在单台节点上运行,对于这种小数据是非常能够提高执行效率的。
C 数据倾斜的优化。
group by
比如使用groupby的情况,我们项目中就是用城市表去join订单表就出现过这种情况。其实并不是所有的聚合都在ruduce端聚合的,很多都可以在map端来聚合的,最终在ruduce端得出结果。我们可以开启 Map 端聚合参数设置:
set hive.map.aggr = true // 开启map端聚合
set hive.groupby.mapaggr.checkinterval = 100000 //聚合的条数
set hive.groupby.skewindata = true //有数据倾斜的时候进行负载均衡
(当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到同一个 Reduce 中,最后完成最终的聚合操作)
count (distinct id)
在数据量大的情况下,由于 COUNT DISTINCT 操作需要用一个Reduce Task 来完成,这一个 Reduce 需要处理的数据量太大,就会导致整个 Job 很难完成,一般 COUNT DISTINCT 会采用先 GROUP BY 再 COUNT 的方式来实现
selectcount(distinct id) from bigtable;
--比如下面这个,采用group by 再count,虽然这种操作会多了一个job完成,但是也是值得的
selectcount(id) from (select id from bigtable groupby id) a;
2.是代码优化
A.表的优化,比如说我们小表去join大表,一般来说我们数仓的维度表数据量比较小,订单表数据量比较大,这样join的话可以让小表先存到内存,走mapjoin,不走ruducejoin,这样就可以大大提升我们join的一个执行效率了。小表的设置的话set hive.mapjoin.smalltable.filesize = 25,000,000(25MB)
B.第二种情况就是大表join大表了,这个怎么优化呢?
可能存在的情况,1,关键字段有空值,比如说id,这个时候我们就要先把空值过滤掉再join
2,如果要觉得有必要要保留这个数据不想过滤掉的话,这个时候我们可以将表中未空的字段赋予一个随机的值,使得数据可以随机均匀的分布到不同的reducer上(比如on 后面是a.id=b.id就可以写成 nvl(a.id,rand())=b.id )
3,如果两个表当中关键字段都没有空的话,就可以用SMB join,就是采用on Join字段分桶后再进行Join。桶的核数一般不超过cup的核数。
C 代码方面是尽量能不用笛卡尔积就不用笛卡尔积(就是两张表没有任何关联字段的情况下joink)
D 第四中就是行列过滤了
列过滤方面就是列值剪裁,减少不必要列字段查询,有分区的话可以使用分区表,然后比如说需要拿到某一天的数据,就按照那天的分区字段来查询,减少全表的扫描,提高数据的查询效率。
行处理方面的话,就可以使用我们常说的谓词下推了。所谓谓词下推就是我们要先过滤不必要参与join的数据,让少点数据参与join然,这样就可以大大提高我们效率。
--一般都是用子查询来先过滤再光联表
select b.idfrom bigtable b
join (select id from bigtable where id <= 10) o on b.id = o.id;
E 分区分桶表的设计。分区是分文件,分桶是分文件夹,两种都可以提升查询效率,但是分区用得比较多(常用就是按天分区),分桶用得比较少(分桶一般可能要进行数据采样或者大表join大表的时候用得上)
3.是存储格式和压缩格式的优化
用列式存储方式比行式存储效率要更高,我们当时数仓项目就是使用了orc的存储格式,有很高的压缩比。所以一般表的设计我们是采用(orc格式+snappy的压缩来进行,而ods层是orc+zlib的压缩来的,zlib写入速度要快些,snappy是读取速度更快写)而且查询任务的时候输入数据量减少,使用的MapTask也就自然减少了。