Hive之count (distinct)剖析与优化

HIVE —— count distinct优化方法

市场部小姐姐:我的sql为啥这么慢呀?
做去重统计时,小姐姐一般都这么写:

select
  count(distinct (bill_no)) as visit_users
from
  i_usoc_user_info_d
where
  p_day = '20200408'
  and bill_no is not null
  and bill_no != ''

这没有毛病,但我们需要注意的是,我们写的是hql,而它的底层引擎是mapreduce,是分布式计算的,所以自然会出现数据倾斜这种分布式计算的典型问题,比如上面的使用数仓中一张沉淀了所有用户信息的融合模型来统计所有的手机号码的个数,这种写法肯定是能跑出结果的,但运行时长似乎有点小长啊~:
在这里插入图片描述
跑出的结果是:177269899
记录数上亿,去hdfs中查看文件发现这个分区大小为55G,并且此时,我们通过查看执行计划和日志可以发现只有一个stage:
Hadoop job information for Stage-1: number of mappers: 226; number of reducers: 1
这里其实熟悉mr原理的已经明白了这条sql跑的慢的原因,因为出现了很严重的数据倾斜,226个mapper,1个reducer,所有的数据在mapper处理过后全部只流向了一个reducer,逻辑计划大概如下:
在这里插入图片描述
为什么只有一个reducer呢,因为使用了distinct和count(full aggreates),这两个函数产生的mr作业只会产生一个reducer,而且哪怕显式指定set mapred.reduce.tasks=100000也是没用的。
所以对于这种去重统计,如果在数据量够大,我的经验一般是一亿记录数以上(视各位同学公司的集群规模,计算能力而定),我都会选择使用count加group by去进行统计:

select
  count(a.bill_no)
from
  (
    select
      bill_no
    from
      dwfu_hive_db.i_usoc_user_info_d
    where
      p_day = '20200408'
      and bill_no is not null
      and bill_no != ''
    group by
      bill_no
  ) a

运行,跑起来,耗时如下:
在这里插入图片描述
我买噶地,168s,速度提升了将近7倍,查看执行计划和日志:
Hadoop job information for Stage-1: number of mappers: 226; number of reducers: 92
Hadoop job information for Stage-2: number of mappers: 88; number of reducers: 1

发现启动了两个stage也就是两个mr作业并且stage1的mapper数量不变,reducer增加为了92,这是因为引入了group by将数据分组到了多个reducer上进行处理。逻辑执行图大致如下:

总结:在数据量很大的情况下,使用count+group by替换count(distinct)能使作业执行效率和速度得到很大的提升,一般来说数据量越大提升效果越明显。

注意:开发前最好核查数据量,可别什么几万条几十万条几十M数据去重统计就count加groupby就咔咔往上写,最后发现速度根本没有直接count(distinct)快,作业还没起起来呢人家count(distinct)就完事结果出来了,所以优化还得建立在一个数据量的问题上,这也是跟其他sql的区别。

发布了14 篇原创文章 · 获赞 1 · 访问量 684

猜你喜欢

转载自blog.csdn.net/qq_33891419/article/details/103019254
今日推荐