Hive优化

Hive优化

一、大表Join大表
1、空KEY过滤

有时 join 超时是因为某些 key 对应的数据太多,而相同 key 对应的数据都会发送到相同 的 reducer 上,从而导致内存不够。此时我们应该仔细分析这些异常的 key,很多情况下, 这些 key 对应的数据是异常数据,我们需要在 SQL 语句中进行过滤。例如 key 对应的字段为 空,操作如下:

创建原始数据空 id 表

// 创建空 id 表
create table nullidtable(id bigint, t bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';

分别加载原始数据和空 id 数据到对应表中

hive (default)> load data local inpath '/opt/module/data/nullid' into table nullidtable;

测试不过滤空 id

hive (default)> insert overwrite table jointable select n.* from nullidtable n left join bigtable o on n.id = o.id;

测试过滤空 id

hive (default)> insert overwrite table jointable select n.* from (select
* from nullidtable where id is not null) n left join bigtable o on n.id = o.id;
2、空KEY转换

有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在 join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地 分不到不同的 reducer 上。例如:

案例实操:

不随机分布空 null 值:

设置 5 个 reduce 个数

set mapreduce.job.reduces = 5;

JOIN 两张表:

insert overwrite table jointable
select n.* from nullidtable n left join bigtable b on n.id = b.id;

结果:可以看出来,出现了数据倾斜,某些 reducer 的资源消耗远大于其 他 reducer。

随机分布空 null 值:

设置 5 个 reduce 个数

set mapreduce.job.reduces = 5;

JOIN 两张表:

insert overwrite table jointable
select n.* from nullidtable n full join bigtable o on nvl(n.id,rand()) = o.id;

结果:可以看出来,消除了数据倾斜,负载均衡 reducer 的资源消耗

3、SMB(Sort Merge Bucket join)

分桶后JOIN

创建第二张大表

create table bigtable2( id bigint,
t bigint, uid string,
keyword string, url_rank int, click_num int, click_url string)
row format delimited fields terminated by '\t';
load data local inpath '/opt/module/data/bigtable' into table bigtable2;

测试大表直接 JOIN

insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url from bigtable s
join bigtable2 b on b.id = s.id;

创建分通表 1,桶的个数不要超过可用 CPU 的核数

create table bigtable_buck1( id bigint,
t bigint, uid string,
keyword string, url_rank int, click_num int, click_url string)
clustered by(id) sorted by(id) into 6 buckets
row format delimited fields terminated by '\t';
load data local inpath '/opt/module/data/bigtable' into table bigtable_buck1;

创建分通表 2,桶的个数不要超过可用 CPU 的核数

create table bigtable_buck2( id bigint,
t bigint, uid string,
keyword string, url_rank int, click_num int, click_url string)
clustered by(id) sorted by(id) into 6 buckets
row format delimited fields terminated by '\t';
load data local inpath '/opt/module/data/bigtable' into table bigtable_buck2;
设置参数
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true; 
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;

测试

insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url from bigtable_buck1 s
join bigtable_buck2 b on b.id = s.id;
二、Group By
默认情况下,Map 阶段同一 Key 数据分发给一个 reduce,当一个 key 数据过大时就倾斜 了。

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

1、开启 Map 端聚合参数设置

是否在 Map 端进行聚合,默认为 True

set hive.map.aggr = true 

在 Map 端进行聚合操作的条目数目

set hive.groupby.mapaggr.checkinterval = 100000 

有数据倾斜的时候进行负载均衡(默认是 false)

set hive.groupby.skewindata = true 

当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出 结果会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果 是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二 个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证 相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。

hive (default)> select deptno from emp group by deptno;

优化以后

hive (default)> set hive.groupby.skewindata = true;
hive (default)> select deptno from emp group by deptno;
2、Count(Distinct) 去重统计

数据量小的时候无所谓,数据量大的情况下,由于 COUNT DISTINCT 操作需要用一个 Reduce Task 来完成,这一个 Reduce 需要处理的数据量太大,就会导致整个 Job 很难完成, 一般 COUNT DISTINCT 使用先 GROUP BY 再 COUNT 的方式替换,但是需要注意 group by 造成 的数据倾斜问题.

案例实操

创建一张大表

hive (default)> create table bigtable(id bigint, time bigint, uid string, keyword
string, url_rank int, click_num int, click_url string) row format delimited
fields terminated by '\t';

加载数据

hive (default)> load data local inpath '/opt/module/data/bigtable' into table bigtable;

设置 5 个 reduce 个数

set mapreduce.job.reduces = 5; 

执行去重 id 查询

hive (default)> select count(distinct id) from bigtable;

采用 GROUP by 去重 id

hive (default)> select count(id) from (select id from bigtable group by id) a;
虽然会多用一个 Job 来完成,但在数据量大的情况下,这个绝对是值得的。
3、笛卡尔积

尽量避免笛卡尔积,join 的时候不加 on 条件,或者无效的 on 条件,Hive 只能使用 1 个

reducer 来完成笛卡尔积。

4、行列过滤

列处理:在 SELECT 中,只拿需要的列,如果有分区,尽量使用分区过滤,少用 SELECT *。

行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在 Where 后面,那么就会先全表关联,之后再过滤,比如: 案例实操:

测试先关联两张表,再用 where 条件过滤

hive (default)> select o.id from bigtable b join bigtable o on o.id = b.id
where o.id <= 10;
# Time taken: 34.406 seconds, Fetched: 100 row(s)

通过子查询后,再关联表

hive (default)> select b.id from bigtable b
join (select id from bigtable where id <= 10) o on b.id = o.id;
# Time taken: 30.058 seconds, Fetched: 100 row(s)
5、复杂文件增加 Map 数

当 input 的文件都很大,任务逻辑复杂,map 执行非常慢的时候,可以考虑增加 Map 数, 来使得每个 map 处理的数据量减少,从而提高任务的执行效率。

增加 map 的方法为:根据

computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M 公式, 调整 maxSize 最大值。让 maxSize 最大值低于 blocksize 就可以增加 map 的个数。

案例实操:

执行查询:

hive (default)> select count(*) from emp;
Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1

设置最大切片值为100个字节

hive (default)> set mapreduce.input.fileinputformat.split.maxsize=100; hive (default)> select count(*) from emp;
Hadoop job information for Stage-1: number of mappers: 6; number of reducers: 1
6、小文件进行合并

在 map 执行前合并小文件,减少 map 数:CombineHiveInputFormat 具有对小文件进行合 并的功能(系统默认的格式)。HiveInputFormat 没有对小文件合并功能。

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

在 Map-Reduce 的任务结束时合并小文件的设置:

在 map-only 任务结束时合并小文件,默认 true

SET hive.merge.mapfiles = true; 

在 map-reduce 任务结束时合并小文件,默认 false

SET hive.merge.mapredfiles = true; 

合并文件的大小,默认 256M

SET hive.merge.size.per.task = 268435456; 

当输出文件的平均大小小于该值时,启动一个独立的 map-reduce 任务进行文件 merge

SET hive.merge.smallfiles.avgsize = 16777216;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值