[Hive]Hive常用的优化方法

目录

 

Hive调优原则

规划阶段优化

Hive表文件的格式

Hive文件及中间文件的压缩方式

根据业务实际需要创建分区表

根据业务实际创建分桶表

数据处理阶段优化

裁剪列

JOIN避免笛卡尔积

启动谓词下推

开启Map端聚合功能

使用Hive合并输入格式

合并小文件

group by数据倾斜

Join数据倾斜

低性能的UDF和SerDe

局部排序

Multiple Insert

启用向量化查询引擎

启用基于代价的优化

使用TABLESAMPLE取样查询

将重复的子查询结果保存到中间表

控制map的数量

控制reduce的数量


Hive调优原则

1)保证map扫描的数据量尽量少

减少map端扫描数量,需要控制待处理的表文件或中间文件的数据量尽量少。优化的方式如:Hive表文件使用高效的文件格式、Hive表文件使用合适的文件压缩格式、中间文件使用合适的文件压缩格式、利用列裁剪、利用分区裁剪、使用分桶。

2)保证map传送给reduce的数据量尽量小

控制map传送给reduce的数据量,是指JOIN避免笛卡尔积、启动谓词下推、开启map端聚合功能。

3)保证map和reduce处理的数据量尽量均衡

保证map处理的数据量尽量均衡,是指使用Hive合并输入格式、必要时对小文件进行合并。保证reduce处理的数据量尽量均衡,是指解决数据倾斜问题。包括解决group by造成的数据倾斜、解决join造成的数据倾斜。

4)合理调整map和reduce占用的计算资源

合理调整map和reduce占用的计算资源,是指通过参数设置合理调整map和reduce的内存及虚拟核数。根据集群总体资源情况,以及分配给当前租户的资源情况,在不影响其他业务正常运行的条件下,最大限度地利用可使用的计算资源。

5)合理调整map和reduce的数量

合理调整map数,是指通过设置每个map处理数据量的最大和最小值来合理控制map的数量。合理调整reduce数,是指通过直接设置reduce数量或通过设置每个reduce的处理数据量来合理控制reduce的数量。

6)重用计算结果

重用计算结果,是指将重复的子查询结果保存到中间表,供其他查询使用,减少重复计算,节省计算资源。

7)使用成熟的Hive优化特性

使用稳定成熟的Hive优化特性,包括:相关性优化器(Correlation Optimizer),基于代价的优化(Cost-based optimization),向量化查询引擎(Vectorized Query Execution),Join相关优化(Map Join、SMB Join),Multiple Insert特性,TABLESAMPLE抽样查询、Limit优化、局部排序(SORT BY、 DISTRIBUTE BY)。

8)使用高效HQL或改用MR

使用高效HQL,包括慎用低性能的UDF和SerDe、优化count(distinct a)。

select a, count(distinct b) from t1 group by a;

改造后:

Select a, count(1) from (Select a,b from t1 group by a,b) t2;

对于使用HQL比较冗余同时性能低下的场景,改用MR效率更高。

规划阶段优化

Hive表文件的格式

(1)使用ORC的场景

ORC文件格式可以提供一种高效的方法来存储Hive数据,运用ORC可以提高Hive的读、写以及处理数据的性能。

以下两种场景谨慎使用ORC:

1)文本文件加载到ORC格式的Hive表的场景:由于文本格式到ORC,需要耗费较高的CPU计算资源,相比于直接落地成文本格式Hive表而言加载性能会低很多;

2)Hive表作为计算结果数据,导出给Hadoop之外的外部系统读取使用的场景:ORC格式的结果数据,相比于文本格式的结果数据而言其易读性低很多。

除以上两种场景外,其他场景均建议使用ORC作为Hive表的存储格式。

(2)使用Parquet的场景

Parquet的核心思想是使用“record shredding and assembly algorithm”来表示复杂的嵌套数据类型,同时辅以按列的高效压缩和编码技术,实现降低存储空间,提高IO效率,降低上层应用延迟。

Parquet是与语言无关的,而且不与任何一种数据处理框架绑定在一起,适配多种语言和组件,能够与Parquet配合的组件有:

查询引擎:Hive、Impala、Pig;

计算框架:MapReduce、Spark、Cascading;

数据模型:Avro、Thrift、Protocol Buffers、POJOs。

对于Impala和Hive共享数据和元数据的场景,建议Hive表存储格式为Parquet

Hive文件及中间文件的压缩方式

GZip和Snappy,这两种压缩算法在大数据应用中最常见,适用范围最广,压缩率和速度都较好,读取数据也不需要专门的解压操作,对编码来说透明。

压缩率跟数据有关,通常从2到5不等;两种算法中,GZip的压缩率更高,但是消耗CPU更高,Snappy的压缩率和CPU消耗更均衡。

对于存储资源受限或要求文件必须压缩的场景,可考虑使用以上两种压缩算法对表文件及中间文件进行压缩。

根据业务实际需要创建分区表

使用分区表能有效地分隔数据,分区条件作为查询条件时,减少扫描的数据量,加快查询的效率。如果业务数据有明显的时间、区域等维度的区分,同时有较多的对应维度的查询条件时,建议按照相应维度进行一级或多级分区。

根据业务实际创建分桶表

分桶的目的是便于高效采样和为Bucket MapJoin及SMB Join做数据准备。

对于Hive表有按照某一列进行采样的场景,建议以该列进行分桶。数据会以指定列的值为key哈希到指定数目的桶中,从而支持高效采样。

对于对两个或多个数据量较大的Hive表按照同一列进行Join的场景,建议以该列进行分桶。当Join时,仅加载部分桶的数据到内存,避免OOM。

 

数据处理阶段优化

裁剪列

当待查询的表字段较多时,选取需要使用的字段进行查询,避免直接select *出大表的所有字段。

JOIN避免笛卡尔积

JOIN场景应严格避免出现笛卡尔积的情况。参与笛卡尔积JOIN的两个表,交叉关联后的数据条数是两个原表记录数之积,对于JOIN后还有聚合的场景而言,会导致reduce端处理的数据量暴增,极大地影响运行效率。

启动谓词下推

谓词下推是一个逻辑优化:尽早的对底层数据进行过滤以减少后续需要处理的数据量。通过以下参数启动谓词下推。

set hive.optimize.ppd=true;

开启Map端聚合功能

在map中会做部分聚集操作,能够使map传送给reduce的数据量大大减少,从而在一定程度上减轻group by带来的数据倾斜。通过以下参数开启map端聚合功能。

 set hive.map.aggr=true;

使用Hive合并输入格式

设置Hive合并输入格式,使Hive在执行map前进行文件合并,使得本轮map处理数据量均衡。通过以下参数设置Hive合并输入格式。

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

合并小文件

小文件较多的map或reduce能够提高并发度,加快任务运行速度;但同时在HDFS上生成的文件数目也会越来越多,给HDFS的NameNode造成内存上压力,进而影响HDFS读写效率。对于集群的小文件(主要由Hive启动的MR生成)过多已造成NameNode压力时,建议在Hive启动的MR中启动小文件合并。

set hive.merge.mapfiles=true;

小文件合并能够使本轮map输出及整个任务输出的文件完成合并,保证下轮MapReduce任务map处理数据量均衡。

group by数据倾斜

方法一:

通过开启group by倾斜优化开关,解决group by数据倾斜问题。

开启优化开关后group by会启动两个MR。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MR Job再根据预处理的数据结果按照Group By Key分布到Reduce中,这个过程可以保证相同的Group By Key被分布到同一个Reduce中,最后完成最终的聚合操作。

日志特征:map 100% reduce99%,一直等待某些数据倾斜的reduce完成。

set hive.map.aggr=true;

set hive.groupby.skewindata=true;

方法二:

把倾斜的关键字提取出来单独处理:倾斜的字段加上一个随机数打散,分阶段进行group by ,最后去掉随机数进行group by

Join数据倾斜

方法一:

两个表关联键的数据分布倾斜,会形成Skew Join。将这类倾斜的特殊值(记录数超过hive.skewjoin.key参数值)不落入reduce计算,而是先写入HDFS,然后再启动一轮MapJoin专门做这类特殊值的计算,期望能提高计算这部分值的处理速度。设置以下参数。

set hive.optimize.skewjoin=true;

set hive.skewjoin.key=100000;

方法二:

把倾斜的关键字提取出来单独处理:倾斜的字段在join两端的表加上相同的随机数打散,分阶段进行join后过滤不必要的数据,最后去掉随机数进行join。

低性能的UDF和SerDe

慎用低性能的UDF和SerDe,主要指谨慎使用正则表达式类型的UDF和SerDe。如:regexp、regexp_extract、regexp_replace、rlike、RegexSerDe。

局部排序

Hive中使用order by完成全局排序,正常情况下,order by所启动的MR仅有一个reducer,这使得大数据量的表在全局排序时非常低效和耗时。

当全局排序为非必须的场景时,可以使用sort by在每个reducer范围进行内部排序。同时可以使用distribute by控制每行记录分配到哪个reducer。

Multiple Insert

使用Multiple Insert特性,减少Map数量,提高效率

From t1

Insert overwrite t2

Select a

Where a>1

Insert overwrite t3

Select b

Where b>1

启用向量化查询引擎

传统方式中,对数据的处理是以行为单位依次处理的。Hive也采用了这种方案。这种方案带来的问题是,针对每一行数据,都要进行数据解析,条件判断,方法调用等操作,从而导致了低效的CPU利用。

向量化特性,通过每次处理1024行数据的列方式处理,从而减少了方法调用,降低了CPU消耗,提高了CPU利用率。结合JDK1.8对SIMD的支持,获得了极高的性能提升。通过以下参数启用向量化查询引擎:

set hive.vectorized.execution.enabled=true;

启用基于代价的优化

基于代价的优化器,可以基于代价(包括FS读写、CPU、IO等)对查询计划进行进一步的优化选择,提升Hive查询的响应速度。

通过以下参数启用基于代价的优化:

set hive.cbo.enabled=true;

 

使用TABLESAMPLE取样查询

在Hive中提供了数据取样的功能,用来从Hive表中根据一定的规则进行数据取样,Hive中的数据取样支持数据块取样和分桶表取样

分块采样:

select * from t1 tablesample(10 percent);

分桶取样:

select * from t1 tablesample(bucket 1 out of 10 on rand());

将重复的子查询结果保存到中间表

对于某些业务场景, HQL语句中可能存在相同的子查询,为避免重复计算浪费计算资源,考虑将重复的子查询的计算结果保存到中间表,实现计算一次、结果共享的优化目标。

控制map的数量

map的数量会影响MapReduce扫描、过滤数据的效率。

对于扫描、过滤数据的逻辑比较复杂、输入数据量较大条数较多的场景:根据集群总体资源情况,以及当前用户的资源可用情况,在不影响其他业务正常运行的条件下,map数量需要适当增大,增加并行处理的力度。

split参数

MR中对文件进行split的公式:splitsize = max(splitsize,min(blocksize,filesize/NUMmaps))每个Map最大输入大小,默认为为HDFS的blocksize。

hive 的split size在使用不同的input format时依赖的参数不同。

(1)hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat

此时由以下三个参数控制

mapred.max.split.size  #控制最大split

mapred.min.split.size.per.node #控制最小split,优先级低

mapred.min.split.size.per.rack #控制最小split,优先级高

(2)hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat

此时由

mapred.min.split.size

mapred.map.tasks #可以忽略,默认为1

控制reduce的数量

reduce数量会影响MapReduce过滤、聚合、对数据排序的效率。

对于关联、聚合、排序时reduce端待处理数据量较大的场景:首先根据每个reduce处理的合适数据量控制reduce的个数,如果每个reduce处理数据仍然很慢,再考虑设置参数增大reduce个数。

1)hive.exec.reducers.bytes.per.reducer

这个参数控制一个job会有多少个reducer来处理,依据的是输入文件的总大小。默认1GB

2)hive.exec.reducers.max

这个参数控制最大的reducer的数量, 如果 input/bytes per reduce > max则会启动这个参数所指定的reduce个数。  这个并不会影响mapre.reduce.tasks参数的设置。默认的max是999

3)mapred.reduce.tasks

这个参数如果指定了,hive就不会用它的estimation函数来自动计算reduce的个数,而是用这个参数来启动reducer。默认是-1.

猜你喜欢

转载自blog.csdn.net/henku449141932/article/details/111480016