[Hive]Hive常用的优化方法

目录

 

Hive调优原则

规划阶段优化

Hive表文件的格式

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

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

根据业务实际创建分桶表

数据处理阶段优化

裁剪列

JOIN避免笛卡尔积

扫描二维码关注公众号,回复: 12364070 查看本文章

启动谓词下推

开启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