Hive-调优策略

1.Fetch抓取

  Fetch抓取是,Hive中对某些情况的查询可以不必使用MapReduce计算;例如像select * from table这种的操作,在这种情况下,Hive可以简单地读取employee对应的存储目录下的文件,然后输出查询结果到控制台;

  在hive-default.xml.template文件中hive.fetch.task.conversion默认是more,老版本hive默认是minimal,该属性修改为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> #我们所使用的2.3.5版本中已无需设置,面试使用

2.本地模式

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

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

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;

    在未开启本地优化的情况下:

      Hive-调优策略

     在开启本地优化的情况下:

      Hive-调优策略

3.表的优化

  3.1 小表&大表join

    将key相对分散,并且数量小的表防在join的左边,这样可以有效减少内存溢出错误发生的几率;在进一步,可以使用group让下的维度表先进内存;在map端完成reduce;

    实际测试发现:新版的hive已经对小表JOIN大表和大表JON小表进行了优化;小表放在左边和右边已经没有明显区别了;

    实例操作:

      (1)需求:测试大表JOIN小表和小表JOIN大小的效率;

      (2)创建大表和创建小表的SQL语句,并导入数据;  

#创建大表
create table bigtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by ‘\t‘;
#创建小表
create table smalltable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by ‘\t‘;
#导入数据
load data local inpath ‘/usr/local/big_data‘ into table bigtable;
load data local inpath ‘/usr/local/small_data‘ into table smalltable;
#创建join后表的语句
create table jointable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by ‘\t‘;

      (3)关闭map join功能

set hive.auto.convert.join = false;

      (4)执行小表关联大表的语句

insert overwrite table jointable
 select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
 from smalltable s
 left join bigtable  b
 on b.id = s.id;

      (5)执行大表关联小表的语句(map join操作可以尝试)

insert overwrite table jointable
  select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
  from bigtable  b
  left join smalltable  s
  on s.id = b.id;

  3.2 Group By优化

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

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

    开启map端集合参数设置:

      (1)是否在map端进行聚合,默认为true;

hive.map.aggr = true

      (2)在map端进行聚合操作的数据条目数目;

hive.groupby.mapaggr.checkinterval = 100000

      (3)有数据倾斜时开启负载均衡;

hive.groupby.skewindata = true

    当选项设定为true,生成的查询计划会有两个MR Job;第一个MR Job中,map的输出结果会随机分布到reduce中,每个reduce做部分聚合操作,并输出结果,从而达到负载均衡的目的;第二个MR Job再根据预处理的数据结果按照group by key分布到reduce中(这个过程可以保证相同的group by key被分布到同一个reduce中),最后完成最终的聚合操作;

  3.3 笛卡尔积

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

Hive本身是不支持笛卡尔积的,不能用select T1.*, T2.* from table_1, table_2这种语法。但有时候确实需要用到笛卡尔积的时候,可以用下面的语法来实现同样的效果:
select T1.*, T2.* from
(select * from table1) T1
join
(select * from table2) T2
on 1=1;
其中on 1=1是可选的,注意在Hive的Strict模式下不能用这种语法,需要先用set hive.mapred.mode=nonstrict;设为非strict模式就可以用了。

  3.4 合理设置map数

    (1)通常情况下,作业会通过input的目录产生一个或者多个map任务;

      主要决定因素有:input的文件总个数,input的文件大小,集群设置的文件块大小;

    (2)是不是map数越多越好

      否,如果一个任务有很多小文件(远远小于块大小128M),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费;而且,同时可执行的map数是受限的;

    (3)是不是保证每个map处理接近128M的文件块,就高枕无忧了

      不一定,比如有一个127M的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时;正对上面的问题2和文艺3,我们需要两种方式来解决:即减少map数和增加map数;

  3.5 小文件进行合并

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

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

  3.6 复杂文件的map数增加

    当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加map数,来使得每个map处理的数量减少,从而提高任务的执行效率;

    增加map的方法为: 

set mapreduce.input.fileinputformat.split.maxsize=100;

    当maxsize小于blocksize时就能够增加map数,blocksize默认为128M;

  3.7 设置reduce的数量

    3.7.1 调整reduce个数方法一

      (1)每个reduce处理的数据量默认256M

hive.exec.reducers.bytes.per.reducer=256000000

      (2)每个任务最大的reduce数,默认为1009

hive.exec.reducers.max=1009

      (3)计算reducer数的公式

N=min(参数2,总输入数据量/参数1)

    3.7.2 调整reduce个数方法二

      (1)在hadoop的mapred-defaule.xml文件修改

      (2)设置每个job的reduce个数

set mapreduce.job.reduces = 15;

    3.7.3 reduce个数并不是越多越好

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

      (2)另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;在设置reduce个数的时候也需要开了这两个原则:

        处理大数据利用合适的reduce个数;使但那个reduce任务处理数据量大小要合适;

相关推荐