1、简单的查询,就是只是select,不带count,sum,group by这样的,都不走map/reduce,直接读取hdfs文件进行filter过滤,即尽量让fetch task(当开启一个Fetch Task功能,就执行一个简单的查询语句不会生成MapRreduce作业,而是直接使用FetchTask,从hdfs文件系统中进行查询输出数据,从而提高效率)任务不走MapReduce。
2、遵循hive的严格模式,禁止以下3种情况的查询模式
(1)当表为分区表时,where子句后无分区字段和限制字段禁止执行
(2)使用order by子句时,必须使用limit语句,因为order by子句只会产生一个reducer任务
(3)限制笛卡尔乘积的查询,尽量将限制条件放在from语句后面的on后面。因为在关系型数据库执行 from join查询的时候不使用on语句而是使用where语句,关系型数据库中优化器可以高效的将where语句转化成那个on语句,但是hive不会执行此优化。故在hive中join操作时尽量将条件放在on后面。
3、优化HiveQL语句,先过滤等。
4、在mapreduce过程中尽量使用压缩,即在map,shuffle,reducer使用snappy压缩。
5、设计好分区表和外部表,创建外部表尽量指定数据所在的文件夹,而不用load去加载。
6、设置map和reducer的任务个数,默认情况是一个块对应一个map任务,一般来说map任务个数不会去调整,而调整reducer的任务个数。reduce处理的数据量大小进行适当调整体现“分而治之”的思想。
7、JVM重用:一个job可能有多个map和reducer任务,每个任务会开启一个jvm虚拟机,默认情况下一个task对应一个jvm,任务完成就销毁jvm,我们可以设置jvm重用参数,这样一个jvm可以连续运行对个任务。
缺点:开启JVM重用将会一直占用使用到的task插槽,以便进行重用,若某个job中的reduce task执行时间要比其他reduce task消耗时间多的话,那么保留的插槽却空闲,无法被其他的job使用,直到所有task都结束才会释放.
8、推测执行:木桶效应,若一个job有10个mapreduce任务,其中9个任务已经完成,那么application Master会在另外一个空闲的容器中运行最后一个相同的任务,哪个运行的快就使用哪个结果,运行慢的就被终止。
9、使用group by代替distinct进行去重
distinct会被hive翻译成一个全局唯一reduce任务来做去重操作,因而并行度为1 而group by则会被hive翻译成分组聚合运算,会有多个reduce任务并行处理,每个reduce对收到的一部分数据组,进行每组聚合(去重)。
count(distinct xxx)只产生一个reduce的优化。由于使用了distinct,导致在map端的combine无法合并重复数据;对于这种count()全聚合操作时,即使设定了reduce task个数,set mapred.reduce.tasks=100;hive也只会启动一个reducer。这就造成了所有map端传来的数据都在一个tasks中执行,成为了性能瓶颈。
10、对表进行join时,要将大表放在后面,小表放在前面或者使用标记来告诉系统谁是大表or谁是小表
SELECT /*streamtable(b)*/ a.key, a.value
FROM a JOIN b ON a.key = b.key
11、在map端完成join(shuffle比较浪费时间,如果没有了reduce也就没有了shuffle)
(1)实现方式
1、在SQL语句中添加Map join标记
select /*+MapJoin(smallTable)*/smallTable.key, bigTable.value
from smallTable JOIN bigTable ON smallTable.key = bigTable.key
会优先将一张小表(默认小于25M,可以需要适当调节)的数据加载进内存中,然后大表的数据通过map端进行读取,然后和内存进行匹配,内存的计算速度很高,这样就在内存端进行了操作,不需要shuffle,不需要reduce
2、自动的mapjoin
set hive.auto.convert.join = true;(该参数为true时,Hive自动对左边的表统计量,如果是小表就加入内存,即对小表使用Map join),其中hive.mapjoin.smalltable.filesize是大小表判断的阈值。