Hive 优化

1 SQL优化

1)列裁剪

        Hive在读数据的时候,可以只读取查询中所需要用到的列,而忽略其他列。

2)分区裁剪

        可以在查询的过程中减少不必要的分区。

3)不同数据类型关联产生的倾斜问题

        不同数据类型id的关联会产生数据倾斜问题。

4)COUNT(DISTINCT)

        计算uv的时候,经常会用到COUNT(DISTINCT),但在数据比较倾斜的时候COUNT(DISTINCT)会比较慢。这时可以尝试用GROUP BY改写代码计算uv。数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替换

5)JOIN操作

        将条目少的表/子查询放在Join操作符的左边。

6)GROUP BY操作

        Map端部分聚合,有数据倾斜时进行负载均衡

7)优化in/exists语句

        hive支持in/exists操作,推荐使用hive的一个高效替代方案:left semi join

8)排序选择

        cluster by: 对同一字段分桶并排序,不能和sort by连用;
        distribute by + sort by: 分桶,保证同一字段值只存在一个结果文件当中,结合sort by 保证每个reduceTask结果有序;
        sort by: 单机排序,单个reduce结果有序
        order by:全局排序,缺陷是只能使用一个reduce

2 设置合理的map reduce的task数量

1)map阶段优化

mapred.min.split.size: 指的是数据的最小分割单元大小;min的默认值是1B
mapred.max.split.size: 指的是数据的最大分割单元大小;max的默认值是256MB
通过调整max可以起到调整map数的作用,减小max可以增加map数,增大max可以减少map数。
需要提醒的是,直接调整mapred.map.tasks这个参数是没有效果的。
set mapred.max.split.size=100000000;(约95M)
set mapred.min.split.size.per.node=100000000;(约95M)
set mapred.min.split.size.per.rack=100000000;(约95M)
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

2) reduce阶段优化

如果设置了mapred.reduce.tasks/mapreduce.job.reduces参数,那么Hive会直接使用它的值作为Reduce的个数;如果mapred.reduce.tasks/mapreduce.job.reduces的值没有设置(也就是-1),那么Hive会根据输入文件的大小估算出Reduce的个数。根据输入文件估算Reduce的个数可能未必很准确,因为Reduce的输入是Map的输出,而Map的输出可能会比输入要小,所以最准确的数根据Map的输出估算Reduce的个数。

1. Hive自己如何确定reduce数:

  reduce个数的设定极大影响任务执行效率,不指定reduce个数的情况下,Hive会猜测确定一个reduce个数,基于以下两个设定:

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

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

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

  即,如果reduce的输入(map的输出)总大小不超过1G,那么只会有一个reduce任务;

2. 调整reduce个数方法一:

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

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

  select pt, count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt;

3. 调整reduce个数方法二:

  set mapred.reduce.tasks=15;

  select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt;

  这次有15个reduce

4. reduce个数并不是越多越好;

  同map一样,启动和初始化reduce也会消耗时间和资源;

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

5. 什么情况下只有一个reduce;

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

  • 没有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’; 这点非常常见,希望大家尽量改写。
  • 用了Order by
  • 有笛卡尔积。

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

3 小文件合并优化

文件数目小,容易在文件存储端造成瓶颈,给HDFS带来压力,影响处理效率。对此,可以通过合并Map和Reduce的结果文件来消除这样的影响。

  用于设置合并的参数有:

  • 是否合并Map输出文件:hive.merge.mapfiles=true(默认值为true)
  • 是否合并Reduce端输出文件:hive.merge.mapredfiles=false(默认值为false)
  • 合并文件的大小:hive.merge.size.per.task=256*1000*1000(默认值为256000000)

Hive优化之小文件问题及其解决方案:

  小文件是如何产生的:

  • 动态分区插入数据,产生大量的小文件,从而导致map数量剧增;
  • reduce数量越多,小文件也越多(reduce的个数和输出文件是对应的);
  • 数据源本身就包含大量的小文件。

  小文件问题的影响:

  • 从Hive的角度看,小文件会开很多map,一个map开一个JVM去执行,所以这些任务的初始化,启动,执行会浪费大量的资源,严重影响性能。
  • 在HDFS中,每个小文件对象约占150byte,如果小文件过多会占用大量内存。这样NameNode内存容量严重制约了集群的扩展。

  小文件问题的解决方案:

 从小文件产生的途径就可以从源头上控制小文件数量,方法如下:

  • 使用Sequencefile作为表存储格式,不要用textfile,在一定程度上可以减少小文件;
  • 减少reduce的数量(可以使用参数进行控制);
  • 少用动态分区,用时记得按distribute by分区;

 对于已有的小文件,我们可以通过以下几种方案解决:

  • 使用hadoop archive命令把小文件进行归档;
  • 重建表,建表时减少reduce数量;
  • 通过参数进行调节,设置map/reduce端的相关参数,如下:
//每个Map最大输入大小(这个值决定了合并后文件的数量)  
set mapred.max.split.size=256000000;    
//一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)  
set mapred.min.split.size.per.node=100000000;  
//一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)    
set mapred.min.split.size.per.rack=100000000;  
//执行Map前进行小文件合并  
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;   

设置map输出和reduce输出进行合并的相关参数:
[java] view plain copy
//设置map端输出进行合并,默认为true  
set hive.merge.mapfiles = true  
//设置reduce端输出进行合并,默认为false  
set hive.merge.mapredfiles = true  
//设置合并文件的大小  
set hive.merge.size.per.task = 256*1000*1000  
//当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。  
set hive.merge.smallfiles.avgsize=16000000

4 存储格式

  可以使用列裁剪,分区裁剪,orc,parquet等这些列式存储格式,因为列式存储的表,每一列的数据在物理上是存储在一起的,Hive查询时会只遍历需要列数据,大大减少处理的数据量。

  Hive支持ORCfile,这是一种新的表格存储格式,通过诸如谓词下推,压缩等技术来提高执行速度提升。对于每个HIVE表使用ORCfile应该是一件容易的事情,并且对于获得HIVE查询的快速响应时间非常有益。

  举一个例子,考虑两个大表A和B(作为文本存储,其中一些列未在此处指定,即行式存储的缺点)以及一个简单的查询,如:

  SELECT A.customerID,A.name,A.age,A.address join B.role,B.department,B.salary ON A.customerID=B.customerID;

  此查询可能需要很长时间才能执行,因为表A和B都以TEXT形式存储,进行全表扫描。

  将这些表格转换为ORCFile格式通常会显着减少查询时间;

  ORC支持压缩存储(使用ZLIB或如上所示使用SNAPPY),但也支持未压缩的存储。

5 压缩格式

大数据场景下存储格式压缩格式尤为关键,可以提升计算速度,减少存储空间,降低网络io,磁盘io,所以要选择合适的压缩格式和存储格式。

压缩的原因

  Hive最终是转为MapReduce程序来执行的,而MapReduce的性能瓶颈在于网络IO和磁盘IO,要解决性能瓶颈,最主要的是减少数据量,对数据进行压缩是个好的方式。压缩虽然是减少了数据量,但是压缩过程要消耗CPU的,但是在Hadoop中,往往性能瓶颈不在于CPU,CPU压力并不大,所以压缩充分利用了比较空闲的CPU。

常用压缩方法对比

 压缩方式的选择

  压缩比率,压缩解压缩速度,是否支持Split

压缩使用

  Job输出文件按照block以Gzip的方式进行压缩:

set mapreduce.output.fileoutputformat.compress=true // 默认值是 false
set mapreduce.output.fileoutputformat.compress.type=BLOCK // 默认值是 Record
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec // 默认值是 org.apache.hadoop.io.compress.DefaultCodec

Map输出结果也以Gzip进行压缩:

set mapred.map.output.compress=true
set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.GzipCodec // 默认值是 org.apache.hadoop.io.compress.DefaultCodec 

对Hive输出结果和中间都进行压缩:

set hive.exec.compress.output=true // 默认值是 false,不压缩
set hive.exec.compress.intermediate=true // 默认值是 false,为 true 时 MR 设置的压缩才启用

6 引擎的选择

hive引擎:Map-Reduce引擎,Apache Tez执行引擎,Hive On Spark引擎。最好的是Hive On Spark引擎。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值