Hive优化

Hive数据倾斜优化总结

Hive数据倾斜优化分为配置优化和SQL优化

优先原则:
  1. 数据不怕多,避免倾斜。
  2. 减少Job数,Job的启动关闭是很耗资源。
  3. 尽量不用Count(distinct) ,效率很低
  4. 定期合并hdfs上的小文件
  5. 设置合理的MR任务数,不是越多越好
  6. 保证全局最优,局部最优不一定是最优

SQL优化

image.png
1.小表join大表

使用MapJoin,让小表进入内存,减少磁盘读写

INSERT OVERWRITE TABLE pv_users 
SELECT /*+ MAPJOIN(pv) */ pv.pageid, u.age 
FROM page_view pv 
JOIN user u ON (pv.userid = u.userid);    

2.大表join大表

处理空值或者某一个倾斜的key

通用方法1:

给它膨胀N倍后加上随机数,在连表的时候保留原有的条件的同时加一个随机数的连接条件,这样可以分散key

Select * from log a
Left outer join (select /*+mapjoin(e)*/
memberid, number 
  From members d
  Join num e
  ) b
On a.memberid= b.memberid
And mod(a.pvtime,30)+1=mber;

上面代码中在连表时候,使用数字表与key少的那张表进行笛卡尔积膨胀了n倍,并且这里使用MapJoin将自定义的小表加载进入内存,然后在原来的连表条件上加上了数字连接的条件,这样原来同一个的key就会被分散为n份到reduce上,这样就避免特别多的key在一个reduce上。

这里的取余函数尤为重要,否则就会出现最后的结果也膨胀了n倍,这样的结果不是我们想要看到的

处理空值

如果你的倾斜的key你发现是null,那就使用下面这种方法,让null值不参与连接

select *
from log a
left outer join bmw_users b
on case when a.user_id is null then concat(‘dp_hive’,rand() ) else a.user_id end = b.user_id;

生成一个随机数给null然后避免它参加连表,只是使用leftjoin将它留下来就可以

当然你也可以单独筛选出null值来unio all,据说那样的效率不如上面的效率

3.减少job数

怎么减少job数呢?首先你的sql要尽可能写的简单,你可以数据分层,一层层向上聚合,那你的每个脚本的job数就减少,然后就是里union all可以合并job数的特性


select * from effect a
join (
  select auction_id as auction_id from auctions
  union all
  select auction_id as auction_id from auctions2
) b
on a.auction_id = b.auction_id;

上面的内层sql中因为auction_id和auction_string_id数据类型不一样,如果你单独去连接effect表后再去合并那就会有3个job数,但是这样先合并就会减少一个job.如果他们是同一张表的id,只是类型不一样,我觉得直接转换类型即可,没必要这样做。网上的人的例子两个id是一张表的,只是类型不一致,我觉得没必要用这种方法

union all 也是有限制的在某些情况是不能合并job的

1.只能union all 非嵌套查询

2.查询中不能join,group by ,count(distinct ) ,当然这些你都是可以想办法搬动的,并不是遇到这些情况就完全不能使用

4.小表不大也不小

如果你的小表只是相对于的大表是小表,相对于你的集群资源还是一个大表,这时候有以上几条

1.如果聚合结果不影响最后的结果,你可以先聚合两张表以减少数量

2.如果你的大表虽然大,但是其实它最后连接的数量并不多,你可以使用小面的代码,先处理大表。

select /*+mapjoin(x)*/* from log a
  left outer join (
    select  /*+mapjoin(c)*/d.*
      from ( select distinct memberid from log ) c
      join members d
      on c.memberid = d.memberid
    ) x
  on a.memberid = b.memberid;

上面代码中,选对日志表中memberid 去重,然后mapjoin members,这样就减少了你直接连接log的数量。这种情况是因为log表示是每个用户的操作日志,那么一个用户操作10次,但是还是一个用户id,这样做就在内层的连接中减少10倍。但是这也是业务上问题,必须你的两张表满足这样的条件,如果不确定的情况下最好用通用方法解决

5.减少oderby的使用,使用ditribute by + sort by

order by是一个reduce进行排序聚合,但是sort by是使用多个reduce分别排序,最后再进行的一个归并排序。

使用sort by的注意事项:

1.首先设置 task,不能为一个

2.使用sort by 你可以指定执行的reduce 个数 (set mapred.reduce.tasks=),对输出的数据再执行归并排序,即可以得到全部结果。

3.ditribute by的字段需要与sort by后面的一致

如下面两种,第一种的结果只是部分有序,第二种

第一种:

SELECT `date`, mediaid, slotid, SUM(mediaclickcost) 
FROM clickcube_mid 
GROUP BY `date`, mediaid, slotid 
DISTRIBUTE BY `date`

SORT BY `date` DESC, mediaid, slotid;

第二种能达到order by的效果

SELECT `date`, mediaid, slotid, SUM(mediaclickcost) 

FROM clickcube_mid GROUP BY `date`, mediaid, slotid 

CLUSTER BY `date` DESC, mediaid, slotid;
6.数据分层的思想

不要想着一步就到位,那样你的sql会非常复杂而且也会效率非常低。学会在表的分层和sql的复杂程度中平衡。一维的去分层只会让你数据架构复杂,学好建模很重要

配置优化

配置 原因
Fetch抓取 简单的select防止它走MR直接读取文件,设置"more"
本地模式 如果数据少可以开启,然后在单台机器上运行
MapJoin 小表加载进入内存减少读写磁盘
Map端聚合 有些聚合操作可以在MAP端完成
动态分区 动态插入分区,使用查询的字段自动进行分区
并行执行 一个查询的多个阶段,不交叉的部分进行并行
严格模式 防止一些效率很低的写法
JVM重用 减少重启JVM的资源消耗
推测执行 推测出执行很久的任务,开启一个备份任务,取先执行完的结果

设置压缩方式与存储格式

比如:数据的存储格式 orc 或者 parquet

​ 压缩方式 snappy

你可能感兴趣的:(Hive优化)