【Hive】(六) Hive 优化策略

一、Fetch抓取

Fetch 抓取是指,Hive 中对某些情况的查询可以不必使用 MapReduce 计算
hive-default.xml.template 文件中 hive.fetch.task.conversion 默认是 more,老版本 hive 默认是 minimal,该属性修改为 more 以后,在全局查找、字段查找、limit 查找 等都不走 mapreduce。

<property> 
	<name>hive.fetch.task.conversion</name> 
	<value>more</value> 
</property>

二、开启本地模式

Hive 可以通过本地模式在单台机
器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。

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

三、语句的优化

1、小表、大表Join

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

2、大表join大表

(1)空 KEY 过滤 有时 join 超时是因为某些 key 对应的数据太多,而相同 key 对应的数据都会发送到相同 的 reducer 上,从而导致内存不够。此时我们应该仔细分析这些异常的 key,很多情况下, 这些 key 对应的数据是异常数据。
(2)空 key 转换 有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在 join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地 分不到不同的 reducer 上

3、MapJoin

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

#设置选择mapjoin
set hive.auto.convert.join = true;
大表小表的阈值设置(默认 25M 以下认为是小表)
set hive.mapjoin.smalltable.filesize=25000000;

4、Group by

   默认情况下,Map 阶段同一 Key 数据分发给一个 reduce,当一个 key 数据过大时就倾 斜了。并不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在 Map 端进行 部分聚合,最后在 Reduce 端得出最终结果

(1)是否在 Map 端进行聚合,默认为 True
hive.map.aggr = true
(2)在 Map 端进行聚合操作的条目数目
hive.groupby.mapaggr.checkinterval = 100000
(3)有数据倾斜的时候进行负载均衡(默认是 false)
hive.groupby.skewindata = true

数据倾斜使用(1)(3)如果以上不管用,可以对倾斜的数据进行单独的sql处理。

  当选项设定为 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 的方式替换。
虽然会多用一个 Job 来完成,但在数据量大的情况下,这个绝对是值得的。

执行去重 id 查询
select count(distinct id) from bigtable;
采用 GROUP by 去重 id
select count(id) from (select id from bigtable group by id) a;

6、笛卡尔积

  当 Hive 设定为严格模式(hive.mapred.mode=strict)时,不允许在 HQL 语句中出现笛卡尔积, 这实际说明了 Hive 对笛卡尔积支持较弱。因为找不到 Join key,Hive 只能使用 1 个 reducer 来完成笛卡尔积
  产生的条件

(1)省略连接条件 
(2)连接条件无效 
(3)所有表中的所有行互相连接

7、行列过滤

  列处理:在 SELECT 中,只拿需要的列,如果有,尽量使用分区过滤,少用 SELECT *。 行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在 Where 后面, 那么就会先全表关联,之后再过滤。
例:

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

四、存储优化

Hive 最终是转为 MapReduce 程序来执行的,而 MapReduce 的性能瓶颈在于网络 IO 和 磁盘 IO,要解决性能瓶颈,最主要的是减少数据量,对数据进行压缩是个好的方式。

text:行存储,默认不压缩,序列化、反序列化开销大
sequence:行存储,二进制,压缩率底
RCfile:行分块,列式存储,解压效率差,读取稍慢
Parquet:列式存储,压缩比率高,但比ORC差,存取速度快
ORC:行分块,列式存储,压缩快,存取快,压缩率最高,RCfile升级版

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 设置的压缩才启用

五、表设计优化

1、创建分区表采用动态分区

分桶针对的是数据文件。

2、创建分桶表

1)创建分桶表

create table stu_buck(
id int,
name string
)clustered by(id) into 4 buckets #分4个桶
row format delimited fields terminated by '\t';

2)设置参数

#开启分桶
set hive.enforce.bucketing=true; 
#-1表示让系统自己决定
set mapreduce.job.reduces=-1;

在这里插入图片描述
3)分桶抽样查询
语法:
TABLESAMPLE(BUCKET x OUT OF y)
x 表示从哪个 bucket 开始抽取,如果需要取多个分区,以后的分区号为当前分区号加上 y;y 必须是 table 总 bucket 数的倍数或者因子。例 如,table 总共分了 4 份,当 y=2 时,抽取(4/2=)2 个 bucket 的数据,当 y=8 时,抽取(4/8=)1/2
个 bucket 的数据
PS:注意:x 的值必须小于等于 y 的值


select * from stu_buck tablesample(bucket 1 out of 4 on id);

六、合并输入输出小文件

–输出合并小文件
set hive.merge.mapredfiles=true;
set hive.merge.smallfiles.avgsize=512000000;
set hive.merge.size.per.task=1024000000; --默认值 256M
– 输入合并小文件,也用于调节map数量
set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; --默认值
set mapred.max.split.size=512000000;
set mapred.min.split.size.per.node=256000000;
set mapred.min.split.size.per.rack=256000000;
set mapred.min.split.size=256000000;

七、参数优化

1、作业有多个可并行的job时,设置任务并行及并行个数:

// 开启任务并行执行
 set hive.exec.parallel=true;
 // 同一个sql允许并行任务的最大线程数 
set hive.exec.parallel.thread.number=8;

2、修改reduce、map个数,
(一般情况下不会修改此参数,可能会造成很多小文件,或者如果reduce资源不够会一直等待,除非比较特殊的任务,前提是排除sql逻辑及数据问题)

设置每个reduce处理的数据量
set hive.exec.reducers.bytes.per.reducer=104857600;
设置reduce个数
set mapred.reduce.tasks=1;
调整最大限制个数
 set hive.exec.reducers.max;
发布了27 篇原创文章 · 获赞 19 · 访问量 1278

猜你喜欢

转载自blog.csdn.net/weixin_42804692/article/details/105695444