【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 中),最后完成最终的聚合操作。

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

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