1 Fetch抓取

       fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算。例如select * from table,这时,hive可以简单的读取table对应的存储目录下的文件,然后输出查询结果到控制台,效率提高。

        方式一,可以在hive-default.xml文件中设置参数hive.fetch.task.conversion为more,该属性设置为more之后,在全局查找、字段查找、limit查找等都不走mapreduce。

<property>
    <name>hive.fetch.task.conversion</name>
    <value>more</value>
    <description>
      Expects one of [none, minimal, more].
      Some select queries can be converted to single FETCH task minimizing latency.
      Currently the query should be single sourced not having any subquery and should not 
      have any aggregations or distincts (which incurs RS), lateral views and joins.
      0. none : disable hive.fetch.task.conversion
      1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
      2. more  : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
    </description>
</property>

        方式二,在hive cli窗口设置参数hive.fetch.task.conversion=more。

hive (default)> set hive.fetch.task.conversion=more;

2 本地模式

       大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过,有时Hive的输入数据量是非常小的。在这种情况下,为查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多。对于大多数这种情况,Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间被明显缩短。

        方式一,可以通过hive-default.xml文件设置hive.exec.mode.local.auto的值为true,来让Hive在适当的时候自动启动这个优化,默认是false。

set hive.exec.mode.local.auto=true;  //开启本地mr
//当输入数据量小于这个值时采用local mr的方式,默认为134217728,即128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
//设置local mr的最大输入文件个数,当输入文件个数小于这个值时采用local mr的方式,默认为4
set hive.exec.mode.local.auto.input.files.max=10;

        方式二,可以通过hive cli窗口设置。

hive (default)> set hive.exec.mode.local.auto=true;

3 JVM重用

       JVM重用是Hadoop调优参数的内容,其对Hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或task特别多的场景,这类场景通常执行时间都很短。

       Hadoop的默认配置通常是使用派生JVM来执行map和Reduce任务的。这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成百上千task任务的情况。JVM重用可以使得JVM实例在同一个job中重新使用N次,N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间,具体多少需要根据具体业务场景测试得出。

<property>
  <name>mapreduce.job.jvm.numtasks</name>
  <value>10</value>
  <description>How many tasks to run per jvm. If set to -1, there is
  no limit. 
  </description>
</property>

       这个功能的缺点是,开启JVM重用将一直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放。如果某个“不平衡的”job中有某几个reduce task执行的时间要比其他Reduce task消耗的时间多的多的话,那么保留的插槽就会一直空闲着却无法被其他的job使用,直到所有的task都结束了才会释放。


4 并行执行

       Hive会将一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。或者Hive执行过程中可能需要的其他阶段。默认情况下,Hive一次只会执行一个阶段。不过,某个特定的job可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个job的执行时间缩短。不过,如果有更多的阶段可以并行执行,那么job可能就越快完成。

       通过设置参数hive.exec.parallel值为true,就可以开启并发执行。不过,在共享集群中,需要注意下,如果job中并行阶段增多,那么集群利用率就会增加。

set hive.exec.parallel=true;              //打开任务并行执行
set hive.exec.parallel.thread.number=16;  //同一个sql允许最大并行度,默认为8。

5 合并小文件

        小文件数目过多,会给hdfs带来压力,并且会影响处理效,可以通过合并Map和Reduce的结果文件来消除这样的影响。

        1) 在map执行前合并小文件,减少map数,CombineHiveInputFormat具有对小文件进行合并的功能。

set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

        2) 在Map-Reduce的任务结束时合并小文件的设置。

// 在map-only任务结束时合并小文件,默认true
SET hive.merge.mapfiles = true;
// 在map-reduce任务结束时合并小文件,默认false
SET hive.merge.mapredfiles = true;
// 合并文件的大小,默认256M
SET hive.merge.size.per.task = 268435456;
// 当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge
SET hive.merge.smallfiles.avgsize = 16777216;

6 合理设置reduce个数

        1. 某些情况下,job运行过程中reduce个数太少,导致任务执行太慢,默认reduce的个数由下面配置控制:

hive.exec.reducers.bytes.per.reducer(每个reduce任务处理的数据量,默认为 1000^3=1G)

hive.exec.reducers.max(每个任务最大的reduce数,默认为999)

        计算reducer数的公式很简单N=min(参数2,总输入数据量/参数1)

        调整reduce的个数

// 调整hive.exec.reducers.bytes.per.reducer参数的值;

set hive.exec.reducers.bytes.per.reducer=500000000; (500M)

// 设置mapred.reduce.tasks 的数量
set mapred.reduce.tasks = 15;

       2. reduce个数并不是越多越好

       同map一样,启动和初始化reduce也会消耗时间和资源;另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题

       3. 什么情况下只有一个reduce

       很多时候你会发现任务中不管数据量多大,不管你有没有设置调整reduce个数的参数,任务中一直都只有一个reduce任务,其实只有一个reduce任务的情况,除了数据量小于hive.exec.reducers.bytes.per.reducer参数值的情况外,还有以下原因:

  1.  没有group by的汇总,比如把select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt; 写成 select count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04';
  2.  用了Order by
  3.  有笛卡尔积

7 排序优化

  1.  Order by 实现全局排序,一个reduce实现,效率低,所以order by过程中尽量limit来限制输出条数。
  2.  Sort by 实现部分有序,单个reduce输出的结果是有序的,效率高,通常和DISTRIBUTE BY关键字一起使用(DISTRIBUTE BY关键字 可以指定map 到 reduce端的分发key)。
  3.  CLUSTER BY col1 等价于DISTRIBUTE BY col1 SORT BY col1。

8 动态分区

       在hive中,有时候会希望根据输入的key,把结果自动输出到不同的目录中,这可以通过动态分区来实现,就是把每一个key当作一个分区。

       如果要启动动态分区,则需要进行下面的设置,首先需要在hive语句中设置允许动态分区。

set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
// 在动态分区有可能很大的情况下,还需要其他的调整
hive.exec.dynamic.partitions.pernode  //参数指的是每个节点上能够生成的最大分区,这个在最坏情况下应该是跟最大分区一样的值
hive.exec.dynamic.partitions.partitions  //参数指的是总共的最大的动态分区数
hive.exec.max.created.files  //参数指的是能够创建的最多文件数
mapred.reduce.tasks  //适当设置reduce个数