Hive调优

1、文件调优

Hive支持的存储数据的格式主要有:TEXTFILE(行存储) 、SEQUENCEFILE(行存储) 、ORC(列存储) 、PARQUET(列存储) 。

  1. textfile格式

    Hive默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用,但使用Gzip这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。

  2. Orc格式

    是Hive 0.11版里引入的新的存储格式。

  3. Parquet格式

    Parquet文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此Parquet格式文件是自解析的。

2、Fetch抓取

Hive中对某些情况的查询可以不必使用MapReduce计算。例如:SELECT * FROM employees;在这种情况下,Hive可以简单地读取employee对应的存储目录下的文件,然后输出查询结果到控制台。

hive-default.xml.template文件中hive.fetch.task.conversion默认是more,老版本hive默认是minimal,该属性修改为more以后,在全局查找、字段查找、limit查找等都不走mapreduce。

3、本地模式

对于大多数这种情况,Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。

用户可以通过设置hive.exec.mode.local.auto的值为true,来让Hive在适当的时候自动启动这个优化,默认是false。

1
2
3
4
5
set hive.exec.mode.local.auto=true;  //开启本地mr
//设置local 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;

4、MapJoin

如果不指定MapJoin或者不符合MapJoin的条件,那么Hive解析器会将Join操作转换成Common Join,即:在Reduce阶段完成join。容易发生数据倾斜。可以用MapJoin把小表全部加载到内存在map端进行join,避免reducer处理。

1
2
3
4
# 开启Mapjoin  ,默认为true
set hive.auto.convert.join = true;
# 大表小表的阈值设置(默认25M一下认为是小表)
set hive.mapjoin.smalltable.filesize=25000000;

5、GroupBy

默认情况下,Map阶段同一Key数据分发给一个reduce,当一个key数据过大时就倾斜了。

并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端进行部分聚合,最后在Reduce端得出最终结果。

1
2
3
4
5
6
# 是否在Map端进行聚合,默认为True
set hive.map.aggr = true
# 在Map端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = 100000
# 有数据倾斜的时候进行负载均衡(默认是false)
set hive.groupby.skewindata = true

6、Count(Distinct) 去重统计

数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT的全聚合操作,即使设定了reduce task个数,set mapred.reduce.tasks=100; hive也只会启动一个reducer。,这就造成一个Reduce处理的数据量太大,导致整个Job很难完成,一般COUNT DISTINCT使用先 GROUP BY再COUNT的方式替换

7、避免笛卡尔积

尽量避免笛卡尔积,join的时候不加on条件,或者无效的on条件,Hive只能使用1个reducer来完成笛卡尔积。

8、行列过滤

列处理:在SELECT中,只拿需要的列,如果有,尽量使用分区过滤,**少用SELECT ** 。

行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在Where后面,那么就会先全表关联,之后再过滤。 简单说就是子查询先写where条件过滤之后在关联查询。

9、动态分区调整

关系型数据库中,对分区表Insert数据时候,数据库自动会根据分区字段的值,将数据插入到相应的分区中,Hive中也提供了类似的机制,即动态分区(Dynamic Partition),只不过,使用Hive的动态分区,需要进行相应的配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 开启动态分区功能(默认true,开启)
hive.exec.dynamic.partition=true
# 设置为非严格模式(动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,
# nonstrict模式表示允许所有的分区字段都可以使用动态分区。)
hive.exec.dynamic.partition.mode=nonstrict
# 在所有执行MR的节点上,最大一共可以创建多少个动态分区。默认1000
hive.exec.max.dynamic.partitions=1000
# 在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。
hive.exec.max.dynamic.partitions.pernode=100
# 整个MR Job中,最大可以创建多少个HDFS文件。默认100000
hive.exec.max.created.files=100000
# 当有空分区生成时,是否抛出异常。一般不需要设置。默认false
hive.error.on.empty.partition=false

10、合理设置Map和Reduce数

调整Map数:

Map数量决定因素:input的文件总个数,input的文件大小,集群设置的文件块大小。

增加map的方法为:根据computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M公式,调整maxSize最大值。让maxSize最大值低于blocksize就可以增加map的个数。

调整Reduce数

过多的启动和初始化reduce也会消耗时间和资源;

另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;

在设置reduce个数的时候也需要考虑这两个原则:处理大数据量利用合适的reduce数;使单个reduce任务处理数据量大小要合适;

1
2
3
4
5
6
# 方法一     公式:N=min(参数2,总输入数据量/参数1)
hive.exec.reducers.bytes.per.reducer=256000000 # 每个Reduce处理的数据量默认是256MB
hive.exec.reducers.max=1009 # 每个任务最大的reduce数,默认为1009
# 方法二
# 在hadoop的mapred-default.xml文件中修改
set mapreduce.job.reduces = 15; # 设置每个job的Reduce个数

11、合并小文件

  1. 在map执行前合并小文件,减少map数:CombineHiveInputFormat具有对小文件进行合并的功能(系统默认的格式)。HiveInputFormat没有对小文件合并功能。

    1
    set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
  2. 在Map-Reduce的任务结束时合并小文件的设置:

    1
    2
    3
    4
    5
    6
    7
    8
    # 在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;

11、并行执行

通过设置参数hive.exec.parallel值为true,就可以开启并发执行。不过,在共享集群中,需要注意下,如果job中并行阶段增多,那么集群利用率就会增加。当然,得是在系统资源比较空闲的时候才有优势,否则,没资源,并行也起不来。

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

12、严格模式

通过设置属性hive.mapred.mode值为默认是非严格模式nonstrict 。开启严格模式需要修改hive.mapred.mode值为strict,开启严格模式可以禁止3种类型的查询。

  1. 对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。
  2. 对于使用了order by语句的查询,要求必须使用limit语句。
  3. 限制笛卡尔积的查询。

13、JVM重用

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

1
2
3
4
5
6
7
8
<!--可以在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>

14、推测执行

设置开启推测执行参数:Hadoop的mapred-site.xml文件中进行配置,默认是true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<property>
<name>mapreduce.map.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some map tasks
may be executed in parallel.</description>
</property>

<property>
<name>mapreduce.reduce.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some reduce tasks
may be executed in parallel.</description>
</property>

Hive本身也可以设置

1
2
3
4
5
<property>
<name>hive.mapred.reduce.tasks.speculative.execution</name>
<value>true</value>
<description>Whether speculative execution for reducers should be turned on. </description>
</property>