hive调优—通用优化策略

本文详细阐述了Hive SQL的优化技巧,包括join操作的小表预加载、mapjoin、桶表连接、谓词下推等,以及groupby中的数据倾斜处理、map端聚合,以及orderby的性能优化策略。还涉及本地模式、JVM重用、并行设置和配置文件调整等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文从hql 语句和参数设置两个方面入手,介绍一些可以通用的优化策略。至于map 和reduce 数量的调整暂不叙述。

配置文件修改:
在当前用户的home目录下创建文件

vim $HOME/.hiverc

hive在每次启动时都会加载文件中的内容使配置生效。
如果希望所有用户都启用配置,可将配置项增加到

$HIVE_HOME/conf/hive-site.xml

一、join优化

1. 小表连大表

hive会假定查询中最后一张表是最大的表,在对每行记录进行连接操作时,会把其他表缓存起来,扫描最后一张表进行计算,因此应该按照表大小从左到右进行连接

2. join 相同条件放在一起

多表连接时,如果每个on 子句都用到同一个连接键,可以在同一个MapReduce job中连接多张表

如下查询都用到A.a作为连接键,以在同一个MapReduce job中连接3张表

select A.a, A.b, B.b, C.b 
from A 
join B on A.a = B.a
join C on A.a = C.a

3. mapjoin

如果只有一张表是小表,可以在最大的表通过mapper的时候将小表完全放到内存中,在map 端执行连接过程,省略掉reduce 过程

set hive.auto.convert.join = true ;

可以通过配置使用这个优化的小表的字节大小

hive.mapjoin.smalltable.filesize = 25000000

右连接和全连接不支持此优化

4. 桶表连接优化

当所有表中的数据都按照on 语句中的连接键进行分桶,且其中一张表中的分桶数是另一张表的倍数,这时hive 可以在map 阶段按分桶数据进行连接,而不需要获取所有数据

set hive.optimize.bucketmapjoin = true

如果所有的分桶表都具有相同的分桶数,而且表中的数据已经按连接键排序过,可以执行分类-合并连接(sort-merge join)的优化,限制条件比较复杂很少用到

set hive.input.format = org.apache.hadoop.hive.ql.io.bucketizedHiveInputFormat;
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;

5. 使用left-semi join

使用left-semi join代替inner join,对于左表中指定的一条数据,右表中一旦找到匹配的记录,便会停止扫描

6. 谓词下推

Predicate Pushdown(PPD)

谓词下推概念中的谓词指返回bool值即true和false的函数,或是隐式转换为bool的函数。下推指把过滤条件下推到map端,提前执行过滤,以减少map到reduce的传输数据,提升整体性能。

即先过滤再join,通过将一些过滤条件尽可能的在最底层执行,可以减少每一层交互的数据量,从而提升性能。

set hive.optimize.ppd = true

谓词下推的规则:

inner join时,谓词任意放都会下推
left join时,左表的谓词应该写在where后,右表的谓词应写在on后
right join时,左表的谓词应该写在on后,右表的谓词应写在where后
full join时,都不会下推

在这里插入图片描述

以left join为例:

会下推优化:

select count(1) from A left join B on A.a = B.a where A.b='c';
select count(1) from A left join B on ( A.a = B.a and B.b='c');

不会下推优化:

select count(1) from A left join B on (A.a = B.a and A.b='c');
select count(1) from A left join B on A.a = B.a where B.b='c';

7. join 字段显式类型转换

当参与join 的字段类型不一致时,hive 会自动进行类型转换,但是自动转换有时候效率并不高,可以根据实际情况通过显式类型转换cast() 函数来避免hive的自动转换。

二、group by优化

1. 数据倾斜

在MapReduce程序中,同一个分组的数据会分配到同一个reduce 操作上去,导致某一些reduce 压力很大,其他的reduce 压力很小,这就是数据倾斜,整个job 执行时间取决于那个执行最慢的reduce。

set hive.groupby.skewindata = true

当选项设定为true,生成的查询计划会有两个MapReduce Job。

第一个job 中,map 的输出结果会随机分布到reduce 中,每个reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的Group By Key有可能被分发到不同的reduce 中,从而达到负载均衡的目的;
第二个job再根据预处理的数据结果按照Group By Key分布到reduce 中,完成最终的聚合操作。

2. map 端聚合

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

set hive.map.aggr = true

map端进行聚合操作的条目数目

set hive.groupby.mapaggr.checkinterval = 100000

三、order by优化

由于是全局排序,order by的操作要在map 后所有的数据都汇集到一个reduce 上执行,导致一个reduce 处理大量数据,如果数据量大执行时间会很久。

在要有进行order by全局排序的需求时:
1.尽量在结果集上排序,避免在中间的大数据集上order by操作;
2.如果需求是取排序后前n 条数据,可以使用distribute by和sort by在各个reduce 上进行排序后取前n条,然后再对各个reduce 的结果集合并后在一个reduce 中全局排序,再取前n条
如:

select id, name from tb_name order by length(name) desc limit 10 ;

可以改写为

select a.id,a.name from
(
	select id,name from tb_name
	distribute by length(name) sort by length(name) desc limit 10
) a 
order by length(a.name) desc limit 10;

四、本地模式

在数据量非常小的情况下,集群触发执行任务的时间可能比实际任务执行的时间更久,这时可以启动本地模式在单台机器上处理所有任务

set hive.exec.mode.local.auto = true ;

五、读取数据不启用MapReduce

启用MapReduce Job是会消耗系统开销的,对于简单的不需要聚合的类似

select col from tb_name limit n ;

不需要起MapReduce job,hive 可以通过直接抓取的方式读取对应表存储目录下的文件,然后输出查询结果到控制台。

set hive.fetch.task.conversion = more ;

  1. minimal:只有 select * 、在分区字段上where 过滤、有limit 这三种场景下才启用直接抓取方式
  2. more:在select、 where 筛选、limit 时,都启用直接抓取方式,建议启用more

六、JVM重用

默认情况下,MapReduce 中一个Map Task或者一个Reduce Task就会启动一个JVM 进程,一个Task 执行完毕后,JVM 进程就退出。 这样如果任务花费时间很短,又要多次启动JVM 的情况下,JVM 的启动时间会变成一个比较大的消耗,这个时候就可以通过重用JVM 来解决。

set mapred.job.reuse.jvm.num.tasks = 3 ; #指定一个JVM 进程在运行几次任务后再退出

七、设置并行

hive会将一个查询转化成多个阶段执行,默认情况下一次只会执行一个阶段,但有些阶段并非相互依赖,可以并行执行,将整个执行时间缩短

set hive.exec.parallel = true ;
set hive.exec.parallel.thread.number = 4 ; #同一条查询允许的最大并行量

八、开启严格模式

set hive.mapred.mode=strict;

hive严格模式有三个限制:

  1. 分区表必须在where条件限制分区
  2. order by语句必须加limit语句
  3. 禁止笛卡尔积连接

九、小文件优化

由于每个小文件都会启动一个map 任务,如果文件过小,以至于map 任务启动和初始化的时间大于逻辑处理的时间,会造成资源浪费,甚至OOM。可以在MapReduce处理的过程对小文件进行合并以及在hadoop中进行归档。

输入合并

set mapred.max.split.size = 256000000; #每个Map最大输入大小,合并文件的数量由此决定
set mapred.min.split.size.per.node = 100000000; #一个节点上split的至少的大小
set mapred.min.split.size.per.rack = 100000000; #一个交换机下split的至少的大小
set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; #执行Map前进行小文件合并

输出合并

set hive.merge.mapfiles = true; #在Map-only的任务结束时合并小文件
set hive.merge.mapredfiles = true; #在MapReduce的任务结束时合并小文件
set hive.merge.size.per.task = 256000000; #合并文件的大小
set hive.merge.smallfiles.avgsize=16000000; #当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge

Hadoop归档文件也是解决小文件问题的方式之一:

set hive.archive.enabled = true ; #启用数据归档
set hive.archive.har.parentdir.settable = true ;
set har.partfile.size=1099511627776; #归档后文件大小

十、建表优化

数据量大建表的时候合理选择分区表和桶表;
尽量采用列式存储,如ORC格式不仅读取性能高还具有压缩效果

十一、一次读取多次插入

有些场景是从一个表读取数据后,要多次利用,这时候就可以使用from … insert into … 语法,将from 前置,只遍历一次hive 表,避免多次读取
如:

from tb_name1
insert overwrite table log1 select a,b,c where d='1'
insert overwrite table log1 select a,b,c where d='2'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值