暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

数仓面试,HQL之数据倾斜问题(三)

媛数据 2021-04-08
2754

 数仓面试中,关于HQL经常会被问到这几个问题:数据倾斜、HQL优化,及其常见的开窗函数(现场会让你写SQL)。这一节,我们来看下HQL数据倾斜这块的问题。


01

                                     hive 数据倾斜基本概念及其原理

  • 什么是hive数据倾斜

    由于数据分布不均匀,造成数据大量的集中到一点,造成数据热点


  • 主要表现

       任务进度长时间维持在 99%或者 100%的附近,查看任务监控页面,发现只有少量 reduce 子任务未完成,因为其处理的数据量和其他的 reduce 差异过大。单一 reduce 处理的记录数和平均记录数相差太大,通常达到好几倍之多,最长时间远大 于平均时长。


  • 底层的原理--关于Map Reduce

案例:

若进行 word count 的文本有100G其中 80G 全部是 “aaa” ,剩下 20G 是其余单词,就会形成 80G 的数据量交给一个 reduce 进行相加,其余 20G 根据 key 不同分散到不同 reduce 进行相加的情况。如此就造成了数据倾斜,临床反应就是 reduce 跑到 99%然后一直在原地等着 那80G reduce 跑完。


主要原因:

hive执行底层转为MapReduce数据处理过程,数据经过 map后,由于不同key 的数据量分布不均,在shuffle 阶段中通过 partition 将相同的 key 的数据打上发往同一个 reducer 的标记,然后开始 spill (溢写)写入磁盘,最后merge成最终map阶段输出文件。


02


 hive 哪些现象容易造成数据倾斜

1)hadoop框架特征:

A、不怕数据大,怕数据倾斜

B、Jobs 数比较多的作业运行效率相对比较低,如子查询比较多

C、 sum,count,max,min 等聚集函数,通常不会有数据倾斜问题


2)产生数据倾斜的原因

  • key分布不均匀;

  • 业务数据本身的特性;

  • 建表时考虑不周;

  • 某些SQL语句本身就有数据倾斜;


3)产生数据倾斜的几种SQL

SQL中下列情况容易出现倾斜:

group by

group by 维度过小,某值的数量过多,造成处理某值的reduce非常耗时

去重 distinct count(distinct xx)

某特殊值过多, 处理此特殊值的reduce耗时

连接 join

这里有两种情形:

小表join大表,其中一个表较小,但是key集中分发到某一个或几个Reduce上的数据远高于平均值

大表与大表,但是分桶的判断字段0值或空值过多这些空值都由一个reduce处理,非常慢


集中于以下使用情况:

  A、group by 不和聚集函数搭配使用的时候

  B、count(distinct),在数据量大的情况下,容易数据倾斜,因为 count(distinct)是按 group by 字段分组,按 distinct 字段排序

  C、 小表关联超大表 join


03


 hive数据倾斜业务场景及其解决方案

1)空值产生的数据倾斜

空值产生数据倾斜,主要在两个表关联的时候,字段出现空值而且还作为关联键;

在日志中,常会有信息丢失的问题,比如日志中的 user_id,如果取其中的 user_id 和用户表中的 user_id 相关联,就会碰到数据倾斜的问题。

把空值的 key 变成一个字符串加上一个随机数

解决方式一:

为空值的这部分 数据 union all 两个表关联的时候,where条件过滤关键键不为空值

select * from log a join user b on a.user_id is not null and a.user_id = b.user_id
union all
select * from log c where c.user_id is null;

解决方式二:

当值为空的时候,用一个随机函数处理,

select * from log a left outer join user b on
case when a.user_id is null then concat('hive',rand()) else a.user_id end = b.user_id;
效率比较:
方法二,log表读取一次,整个运行IO少,job数是1;效率更高
方法一,log表读取两次,整个运行IO多,job数是2;效率更低

2)不同数据类型关联产生数据倾斜
用户表中 user_id 字段为 int,log 表中 user_id 为既有 string 也有 int 的类型, 当按照两个表的 user_id 进行 join 操作的时候,默认的 hash 操作会按照 int 类型的 id 进 行分配,这样就会导致所有的 string 类型的 id 就被分到同一个 reducer 当中
把数字类型 id 转换成 string 类型的 id
select * from user a left outer join log b on b.user_id = cast(a.user_id as string)

3)大小表关联查询产生数据倾斜 
注意:使用map join解决小表关联大表造成的数据倾斜问题。这个方法使用的频率很高。
map join 概念:将其中做连接的小表(全量数据)分发到所有 MapTask 端进行 Join,从 而避免了 reduceTask,前提要求是内存足以装下该全量数据
怎么设置?
hive0.11 版本以前 ---要在写的SQL里面加mapjoin
SELECT关键字后面添加/*+ MAPJOIN(tablelist) */提示优化器转化为map join
select /* +mapjoin(a) */ a.id aid, name, age from a join b on a.id = b.id;
select /* +mapjoin(movies) */ a.title, b.rating from movies a join ratings b on a.movieid =
b.movieid;
hive0.11 版本以后 ---开启参数即可

set hive.auto.convert.join=true; 设置 MapJoin 优化自动开启

set hive.mapjoin.smalltable.filesize=25000000


小表join大表:开启mapjoin,设置参数
大大表关联:把大表切分成小表,然后分别 map join
小表不大不小 join 大表:
如果小表很大,大到 map join 会出现 bug 或异常,需要特殊处理
比如:
users 表有 600w+的记录,把 users 分发到所有的 map 上也是个不小的开销,而且 map join 不支持这么大的小表。如果用普通的 join,又会碰到数据倾斜的问题。
改进方案:
select /*+mapjoin(x)*/* from log a
left outer join (
select /*+mapjoin(c)*/ d.*
from ( select distinct user_id from log ) c join users d on c.user_id = d.user_id
) x
on a.user_id = x.user_id;
假如,log 里 user_id 有上百万个,这就又回到原来 map join 问题。所幸,每日的会员 uv 不会太多,有交易的会员不会太多,有点击的会员不会太多,有佣金的会员不会太多等 等。所以这个方法能解决很多场景下的数据倾斜问题。



总结:
这一节我们讲了关于HIVE数据倾斜的相关问题,要理解好这类问题,抓住核心就是MR底层原理,还有解决Key分布不均匀,集中于热点问题。
下一节我们来总结下hive的其它问题,也是根据常见的面试问题点。



#我是媛姐,一枚有多年大数据经验的程序媛,打过螺丝搬过砖,关注数仓,关注分析。愿你我走得更远!
文章转载自媛数据,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论