Hive的企业级调优

文章目录

    • 一、本地模式
    • 二、表的优化
        • 1、小表、大表Join
        • 2、大表 join 大表
        • 3、MapJoin
        • 4、Group By(数据倾斜解决)
            • (1)开启Map端聚合参数设置
            • (2)原理:
        • 5、Count(Distinct) 去重统计
        • 6、笛卡尔积
        • 7、行列过滤
        • 8、动态分区调整
    • 三、数据倾斜
        • 1、 合理设置Map数
            • (1)通常情况下,作业会通过input的目录产生一个或者多个map任务
            • (2)是不是map数越多越好?
            • (3)是不是保证每个map处理接近128m的文件块,就高枕无忧了?
        • 2、合理设置Reduce数
            • (1)调整reduce个数(方法一)
            • (2)调整reduce个数(方法二)
    • 四、 并行执行
    • 五、严格模式
    • 六、JVM重用
    • 七、执行计划(Explain) (搜索)
        • 1、基本语法
        • 2、案例实操

一、本地模式

有时Hive的输入数据量是非常小,那么,它为查询触发执行任务消耗的时间 可能会比实际job的执行时间要多的多。对于大多数这种情况,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;

二、表的优化

1、小表、大表Join

  • 尽量的将小表放在join的前面
  • 将key相对分散,并且数据量小的表放在join的左边,这样可以有效减少内存溢出错误发生的几率
  • 再进一步,可以使用map join让小的维度表(1000条以下的记录条数)先进内存。在map端完成reduce。

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


2、大表 join 大表

有时join超时是因为某些key对应的数据太多,而相同key对应的数据都会发送到相同的reducer上,从而导致内存不够。

  • 空KEY过滤
    我们应该仔细分析这些异常的key,很多情况下,这些key对应的数据是异常数据,我们需要在SQL语句中进行过滤。例如key对应的字段为空,操作如下:
    案例实操

  • 空key转换
    有时虽然某个key为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join的结果中,此时我们可以表a中key为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的reducer上。例如:

随机分布空null值
(1)设置5个reduce个数
set mapreduce.job.reduces = 5;
(2)JOIN两张表
insert overwrite table jointable
select n.* from nullidtable n full join ori o on
case when n.id is null then concat(‘hive’, rand()) else n.id end = o.id;

结果:如图6-14所示,可以看出来,消除了数据倾斜,负载均衡reducer的资源消耗


3、MapJoin

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

// 1)设置自动选择Mapjoin
set hive.auto.convert.join = true;// 默认为true

// 2)大表小表的阈值设置(默认25M一下认为是小表):
set hive.mapjoin.smalltable.filesize=25000000;

MapJoin工作机制:
Hive的企业级调优_第1张图片


4、Group By(数据倾斜解决)

  • 默认情况下,Map阶段同一Key数据分发给一个reduce,当一个key数据过大时就倾斜了。
  • 并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端进行部分聚合,最后在Reduce端得出最终结果。
(1)开启Map端聚合参数设置
// 1)是否在Map端进行聚合,默认为True
hive.map.aggr = true

// 2)在Map端进行聚合操作的条目数目
hive.groupby.mapaggr.checkinterval = 100000

// 3)有数据倾斜的时候进行负载均衡(默认是false)
hive.groupby.skewindata = true
(2)原理:
当选项设定为 true,生成的查询计划会有两个MR Job。
  • 第一个MR Job中,Map的输出结果会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的
  • 第二个MR Job再根据预处理的数据结果按照Group By Key分布到Reduce中(这个过程可以保证相同的Group By Key被分布到同一个Reduce中),最后完成最终的聚合操作。

5、Count(Distinct) 去重统计

  • 数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成
  • 一般Count Distinct使用先Group By再Count的方式替换。
-- 执行去重id查询
 select count(distinct id) from bigtable;

-- 采用GROUP by去重id
select count(id) from (select id from bigtable group by id) a;

虽然会多用一个Job来完成,但在数据量大的情况下,这个绝对是值得的。


6、笛卡尔积

  • join的时候不加on条件,或者无效的on条件

尽量避免笛卡尔积,Hive只能使用1个reducer来完成笛卡尔积。


7、行列过滤

  • 列处理:在SELECT中,只拿需要的列,如果有,尽量使用分区过滤,少用SELECT *。
  • 行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在Where后面,那么就会先全表关联,之后再过滤,比如:
-- 测试先关联两张表,再用where条件过滤
select o.id from bigtable b 
join ori o on o.id = b.id 
where o.id <= 10;

Time taken: 34.406 seconds, Fetched: 100 row(s)

-- 通过子查询后,再关联表
select b.id from bigtable b
join (select id from ori where id <= 10 ) o on b.id = o.id;

Time taken: 30.058 seconds, Fetched: 100 row(s)

8、动态分区调整

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

// 1)开启动态分区功能(默认true,开启)
hive.exec.dynamic.partition=true

// 2)设置为非严格模式(动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。)
hive.exec.dynamic.partition.mode=nonstrict

// 3)在所有执行MR的节点上,最大一共可以创建多少个动态分区。
hive.exec.max.dynamic.partitions=1000

// 4)在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。
//比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值100,则会报错。
hive.exec.max.dynamic.partitions.pernode=100

// 5)整个MR Job中,最大可以创建多少个HDFS文件。
hive.exec.max.created.files=100000

// 6)当有空分区生成时,是否抛出异常。一般不需要设置。
hive.error.on.empty.partition=false

三、数据倾斜

主要分为map端倾斜和reduce端倾斜,map端倾斜主要是因为输入文件大小不均匀导致,reduce端主要是partition不均匀导致。

1、 合理设置Map数

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

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

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

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

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

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

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

答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。

针对上面的问题2和3,我们需要采取两种方式来解决:即减少map数和增加map数

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

  • 增加map的方法为:根据computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M公式,调整maxSize最大值。让maxSize最大值低于blocksize就可以增加map的个数。
# 设置最大切片值为100个字节
set mapreduce.input.fileinputformat.split.maxsize=100;

2、合理设置Reduce数

(1)调整reduce个数(方法一)
# 1)每个Reduce处理的数据量默认是256MB
hive.exec.reducers.bytes.per.reducer=256000000

# 2)每个任务最大的reduce数,默认为1009
hive.exec.reducers.max=1009

# 3)计算reducer数的公式
N=min(参数2,总输入数据量/参数1)
(2)调整reduce个数(方法二)
# 在hadoop的mapred-default.xml文件中修改,设置每个job的Reduce个数
set mapreduce.job.reduces = 15;

reduce个数并不是越多越好?

  • 过多的启动和初始化reduce也会消耗时间和资源;
  • 有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;
  • 在设置reduce个数的时候也需要考虑这两个原则:处理大数据量利用合适的reduce数;使单个reduce任务处理数据量大小要合适;

四、 并行执行

  • 在共享集群中,需要注意下,如果job中并行阶段增多,那么集群利用率就会增加。
  • 当然,得是在系统资源比较空闲的时候才有优势,否则,没资源,并行也起不来
 #打开任务并行执行
set hive.exec.parallel=true;   
   
 #同一个sql允许最大并行度,默认为8     
set hive.exec.parallel.thread.number=16; 

五、严格模式

Hive提供了一个严格模式,可以防止用户执行那些可能意想不到的不好的影响的查询。

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

<property>
    <name>hive.mapred.modename>
    <value>strictvalue>
    <description>
      The mode in which the Hive operations are being performed. 
      In strict mode, some risky queries are not allowed to run. They include:
        Cartesian Product.
        No partition being picked up for a query.
        Comparing bigints and strings.
        Comparing bigints and doubles.
        Orderby without limit.
    description>
property>
  • 对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。
  • 对于使用了order by语句的查询,要求必须使用limit语句。
  • 限制笛卡尔积的查询。

六、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.numtasksname>
  <value>10value>
  <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都结束了才会释放。


七、执行计划(Explain) (搜索)

1、基本语法

EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query

2、案例实操

  • 查看下面这条语句的执行计划
explain select * from emp;
explain select deptno, avg(sal) avg_sal from emp group by deptno;
  • 查看详细执行计划
explain extended select * from emp;
explain extended select deptno, avg(sal) avg_sal from emp group by deptno;

你可能感兴趣的:(工具杂谈)