目录
Hive优化count(distinct)
SELECT COUNT( DISTINCT id ) FROM TABLE_NAME WHERE ...;
由于引入了DISTINCT,因此在Map阶段无法利用combine对输出结果消重,必须将id作为Key输出,在Reduce阶段再对来自于不同Map Task、相同Key的结果进行消重,计入最终统计值。
这个作业运行时的Reduce Task个数为1,对于统计大数据量时,这会导致最终Map的全部输出由单个的ReduceTask处理。这唯一的Reduce Task需要Shuffle大量的数据,并且进行排序聚合等处理,这使得它成为整个作业的IO和运算瓶颈。
尝试通过显式地增大Reduce Task个数来提高Reduce阶段的并发。具体设置如下:
set mapred.reduce.tasks=100
但这一参数并没有影响实际Reduce Task个数,Hive运行时输出“Number of reduce tasks determined at compile time: 1”。因为Hive在处理COUNT这种“全聚合(full aggregates)”计算时,它会忽略用户指定的Reduce Task数,而强制使用1。
解决方案:转换为子查询,转化为两个MapReduce任务,先select distinct的字段,然后在count(),这样去重就会分发到不同的reduce块,count依旧是一个reduce但是只需要计数即可。
SELECT COUNT(*) FROM (SELECT DISTINCT id FROM TABLE_NAME WHERE … ) t;
补充:count(distinct user_id)
和count...group by user_id
的区别?
首先要清楚count(distinct) 的原理机制,它是将数据通过map端发往一个reduce,之后reduce接收到数据之后,会将数据放入到hashset中去重,之后cleanUp()方法再执行最后的逻辑,比如:计算hashset的size等。这里就出现了一些问题:
1)数据都发往一个reduce会造成数据倾斜
2)程序从分布式变成单机程序,影响效率
3)程序执行过程中,只产生一个job
但也不是绝对的,当数据量很小的时候,此时我们并不需要采分布式执行,一个job运行足矣。但是,当数据量比较大的时候,这时count(distinct) 就暴露除了大大的弊端,所以,此时,不应该采用此法来实现去重。count()…group() by当数据量比较大的时候,采用此法,先分组,这时已经在map端实现了去重机制,之后数据发往reduce 数据量已经变得很小了,并且此法涉及到shuffle ,所以reduce的压力不会集中在某个上,并且会产生多个job 。
group() by count() 一定比count(distinct) 性能要好吗?
不一定,当数据量比较大的时候采用group() by count() 会比count(distinct) 要好,但是在数据量比较小的时候,一个 job就可以处理,没必要用两个job ,也没必要shuffle,所以调优看情况而定。
Hive语句的运行机制包含where、having、group by、order by,执行过程顺序
1.where xx对全表数据做筛选
2.针对结果集使用group by分组
3.针对每个分组进行select查询,有几组就执行几次
4.再进行having筛选每组数据
5.最后整体进行order by排序
补充:Hive语句在MapReduce是怎么运行的,Map端输出的key-value值具体是什么?类似wordcount,MapReduce的输入输出对应什么?(把MR中的分组,排序说一下,要对MR中map(),reduce()和shuffle熟悉)
Hive的MetaStore的三种模式
- 内嵌Derby方式
这个是Hive默认的启动模式,一般用于单元测试,这种存储方式有一个缺点:在同一时间只能有一个进程连接使用数据库 - Local方式
例如本地MySQLÿ