hive中select count(distinct xx) from table 查询慢原因及优化

本文分析了在Hive中使用`select count(distinct xx) from table`查询慢的问题,原因是单个Reduce Task处理大量数据导致IO瓶颈。通过拆分为两个阶段的查询并增大Reduce并发数,可以显著提升效率。优化后的SQL语句将distinct操作提前到第一阶段,减少第二阶段的数据量,从而缩短执行时间。
摘要由CSDN通过智能技术生成

一.问题描述

在hive中,如果数据量很大,select count(distinct xx) from table 有时会查询非常慢
举例说明:
表名:loan_trans
数据量:551353635
存储空间:52.93GB

select count(distinct id)
from loan_trans
where etl_tx_dt =20200202

number of mappers: 228; number of reducers: 1
执行开始时间-结束时间: 7:48-7:57
执行结果:3282768

二.分析原因

该语句转化为MapReduce作业后执行示意图如下
在这里插入图片描述
由于引入了DISTINCT,因此在Map阶段无法利用combine对输出结果消重,必须将id作为Key输出,在Reduce阶段再对来自于不同Map Task、相同Key的结果进行消重,计入最终统计值。
我们看到作业运行时的Reduce Task个数为1,对于统计大数据量时,这会导致最终Map的全部输出由单个的ReduceTask处理。这唯一的Reduce Task需要Shuffle大量的数据,并且进行排序聚合等处理,这使得它成为整个作业的IO和运算瓶颈
经过上述分析后,我们尝试显式地增大Reduce Task个数来提高Reduce阶段的并发,使每一个Reduce Task的数据处理量控制在2G左右。具体设置如下:

set mapred.reduce.tasks=100

调整后我们发现这一参数并没有影响实际Reduce Task个数,Hive运行时输出“Number of reduce tasks determined at compile time: 1”。原来Hive在处理COUNT这种“全聚合(full aggregates)”计算时,它会忽略用户指定的Reduce Task数,而强制使用1

三.优化

我们只能采用变通的方法来绕过这一限制。我们利用Hive对嵌套语句的支持,将原来一个MapReduce作业转换为两个作业,**在第一阶段选出全部的非重复id,在第二阶段再对这些已消重的id进行计数。这样在第一阶段我们可以通过增大Reduce的并发数,并发处理Map输出。在第二阶段,由于id已经消重,因此COUNT(*)操作在Map阶段不需要输出原id数据,只输出一个合并后的计数即可。这样即使第二阶段Hive强制指定一个Reduce Task,极少量的Map输出数据也不会使单一的Reduce Task成为瓶颈。**改进后的SQL语句如下:

select count(*)
from
(
select
id
from loan_trans
where etl_tx_dt =20200202
group by id
) t
<
  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值