Hive高级查询(group by、 order by、 join等)

本文详细介绍了Hive SQL中常用的操作如groupby、orderby、join等的使用方法及注意事项,包括它们的底层实现原理和执行流程。

查询操作

group byorder byjoin 、 distribute by、
sort by、 clusrer byunion all
 
  • 1
  • 2
  • 1
  • 2

底层的实现 
mapreduce

常见的聚合操作

count计数

count(*)    所有值不全为NULL时,加1操作
count(1)    不管有没有值,只要有这条记录,值就加1
count(col)  col列里面的值为null,值不会加1,这个列里面的值不为NULL,才加1
 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

sum求和 
sum(可转成数字的值) 返回bigint

avg求平均值 
avg(可转成数字的值)返回double

distinct不同值个数 
count(distinct col)

order by

按照某些字段排序 
样例

select col1,other...
from table
where conditio
order by col1,col2 [asc|desc]
 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

注意 
order by后面可以有多列进行排序,默认按字典排序 
order by为全局排序 
order by需要reduce操作,且只有一个reduce,与配置无关。数据量很大时,慎用。

执行流程 
 
从表中读取数据,执行where条件,以col1,col2列的值做成组合key,其他列值作为value,然后在把数据传到同一个reduce中,根据需要的排序方式进行。

group by

按照某些字段的值进行分组,有相同值放到一起。

样例

select col1 [,col2] ,count(1),sel_expr(聚合操作)from table
where condition         -->Map端执行
group by col1 [,col2]   -->Reduce端执行
[having]                -->Reduce端执行
 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

注意 
select后面非聚合列,必须出现在group by中 
select后面除了普通列就是一些聚合操作 
group by后面也可以跟表达式,比如substr(col)

特性 
使用了reduce操作,受限于reduce数量,设置reduce参数mapred.reduce.tasks 
输出文件个数与reduce数相同,文件大小与reduce处理的数据量有关。

问题 
网络负载过重 
数据倾斜,优化参数Hive.groupby.skewindata为true,会启动一个优化程序,避免数据倾斜。

执行流程 
 
从表中读取数据,执行where条件,以col1列分组,把col列的内容作为key,其他列值作为value,上传到reduce,在reduce端执行聚合操作和having过滤。

eg:

set mapred.reduce.tasks=5;
select * from TabOrder order by ch asc,num desc;

set mapred.reduce.tasks=3;
select ch ,count(1) as num from TabOrder group by ch;

set hive.groupby.skewindata = true;
select ch ,count(1) as num from TabOrder group by ch having count(1)>2;

select col from tablename group by col; <==> select distinct col from tablename;
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Join表连接

两个表m,n之间按照on条件连接,m中的一条记录和n中的一条记录组成一条新记录。

join等值连接(内连接),只有某个值在m和n中同时存在时。

left outer join左外连接,左边表中的值无论是否在b中存在时,都输出;右边表中的值,只有在左边表中存在时才输出。

right outer joinleft outer join相反。

left semi join类似exists。即查找a表中的数据,是否在b表中存在,找出存在的数据。

mapjoin:在map端完成join操作,不需要用reduce,基于内存做join,属于优化操作。

select m.col as col1, m.col2 as col2, n.col3 as col3 from
(select col1,col2 from,test where ...   (map端执行)
)m  (左表)
[left outer |right outer | left semi] join
n   (右表)
on m.col=n.col
where condition     (reduced端执行)

set hive.optimize.skewjoin=true;
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

读取数据执行where条件,按col列分组,把col列的内容作为key,其他列作为value,传到reduce,在reduce端执行连接操作和where过滤。

eg:

create table m(
ch string,
num string
)
row format delimited 
fields terminated by '\t' 
lines terminated by '\n' 
stored as textfile;
load data local inpath '/liguodong/hivedata/m' into table m;
create table n(
ch string,
num string
)
row format delimited 
fields terminated by '\t' 
lines terminated by '\n' 
stored as textfile;
load data local inpath '/liguodong/hivedata/n' into table n;
select * from m;
select * from n;

内连接
select s.ch,s.num,t.num from
(select ch,num from m)s
join
(select ch,num from n)t
on s.ch=t.ch;

左外连接
select s.ch,s.num,t.num from
(select ch,num from m)s
left outer  join
(select ch,num from n)t
on s.ch=t.ch;

右外连接
select s.ch,s.num,t.num from
(select ch,num from m)s
right outer  join
(select ch,num from n)t
on s.ch=t.ch;

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

 
数据输出对比 

select s.ch,s.num from
(select ch,num from m)s
left semi join
(select ch,num from n)t
on s.ch=t.ch;
运行结果:
A       1
C       5
C       3
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
MapJoin

mapjoin(map side join) 
在map端把小表加载到内存中,然后读取大表,和内存中的小表完成连接操作。其中使用了分布式缓存技术。

优点 
不消耗集群的reduce资源(reduce相对紧缺)。 
减少了reduce操作,加快程序执行。 
降低网络负载。

缺点 
占用部分内存,所以加载到内存中的表不能过大,因为每个计算节点都会加载一次。 
生成较多的小文件。

执行流程 
 
从大表读取数据,执行where条件。把小表加载到内存中,每读取大表中的一条数据,都要和内存中的小表数据进行比较。

第一种方式,自动方式 
配置以下参数 
hive**自动**根据sql,选择使用common join或者map join

set hive.auto.convert.join=true;
hive.mapjoin.smalltable.filesize默认值是25mb
 
  • 1
  • 2
  • 1
  • 2

第二种方式,手动指定

select /*+mapjoin(n)*/ m.col, m.col2, n.col3 from m
join n on m.col=n.col;
 
  • 1
  • 2
  • 1
  • 2

注意:/*+mapjoin(n)*/不能省略,只需替换表名n值即可。

简单总结一下,map join的使用场景: 
1、关联操作中有一张表非常小 
2、不等值的链接操作

select c.city,p.province 
from
(select province,city from city)c
join
(select province from province)p
on c.province=p.province;

mapjoin手动方式
select /*+mapjoin(p)*/ c.city,p.province 
from
(select province,city from city)c
join
(select province from province)p
on c.province=p.province;
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

比较二则的比较时间。

Hive分桶JOIN 
对于每一个表(table)或者分区,Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。 
Hive是针对某一列进行分桶。 
Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。 
好处 
获得更高的查询处理效率。 
使取样(sampling)更高效。

create table bucketed_user
(
id  int,
name  string
)
clustered by (id) sorted by (name) into 4 buckets
row format delimited fields terminated by '\t' 
stored as textfile;

set hive.enforce.bucketing=true;
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

分桶的使用

select * from bucketed_user tablesample(bucket 1 out of 2 on id)
 
  • 1
  • 1

bucket join

set hive.optimize.bucketmapjoin=true;
set hive.optimize.bucketmapjoin.sortedmerge=true;
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

连接两个在(包含连接列)相同列上划分了桶的表,可以使用Map端连接(Map side join)高效的实现。比如JOIN操作。 
对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了捅操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大减少JOIN的数据量。 
对于map端连接的情况,两个表以相同方式划分桶。处理左边表内某个桶的mapper知道右边表内相匹配的行在对应的桶内。因此,mapper只需要获取那个桶(这只是右边表内存储数据的·小部分)即可进行连接。 
这一优化方法并不一定要求两个表必须桶的个数相同,两个表的桶个数是倍数关系也可以。

distribute by、sort by

distribute 分散数据 
distribute by col – 按照col列把数据分散到不同的reduce。

Sort排序 
sort by col – 按照col列把数据排序

select col1,col2 from M
distribute by col1
sort by col1 asc,col2 desc
 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

两者结合出现,确保每个reduce的输出都是有序的。

distribute by与group by对比 
都是按key值划分数据 
都使用reduce操作 
**唯一不同的是**distribute by只是单纯的分散数据,而group by把相同key的数据聚集到一起,后续必须是聚合操作。

order by与sort by 对比 
order by是全局排序 
sort by只是确保每个reduce上面输出的数据有序。如果只有一个reduce时,和order by作用一样。

执行流程 
 
从表中读取数据,执行where条件。 
设置reduce数为3,以distribute by列的值作为key,其他列值作为value,然后把数据根据key值传到不同的reduce,然后按sort by字段进行排序。

应用场景 
map输出的文件大小不均 
reduce输出文件大小不均 
小文件过多 
文件超大

把一个大文件放到一些小文件中
set mapred.reduce.tasks=5;-->下面的city将会输出到五个文件中

insert overwrite table city
selsct time,country,province,city from info
distribute by province;


把一些小文件放到一个大文件中
set mapred.reduce.tasks=1;-->下面的province将会输出到一个大文件中
insert overwrite table province partition(dt='20150719')
selsct time,country,province from city 
distribute by country;

注:province是一个分区表。
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

cluster by

把有相同值的数据聚集到一起,并排序。 
效果等价于distribute by col sort by col 
cluster by col <==> distribute by col sort by col

union all

多个表的数据合并成一个表,hive不支持union

select col from(
select a as col from t1
union all
select b as col from t2
)tmp
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

执行流程 
 
从表中读取数据,执行where条件。合并到同一个表中。

union all必须满足如下要求 
字段名字一样 
字段类型一样 
字段个数一样 
子表不能有别名 
如果需要从合并之后的表中查询数据,那么合并的表必须要有别名

select * from (
select * from m
union all
select * from n
)temp;

如果两张表的字段名不一样,要将一个表修改别名同另一个表的字段名一样。
select * from (
select col1,col2 from m
union all
select col1,col3 as col2 from n
)temp;
<think>首先,用户的问题是:在Hive中,先进行group by操作再进行join on操作,与先进行join on操作再进行group by操作的效率对比。我需要基于提供的引用内容来回答。 回顾引用内容: - 引用[1]:讨论了group by的优化,提到了数据倾斜问题。Hive有一个配置项hive.groupby.skewindata来处理group by时的数据倾斜,它使用两个MR job。但建议优化查询语句。 - 引用[2]:讨论了Hivegroup byjoin、distinct的实现原理。提到order by和sort by的区别,以及distribute by用于控制数据分发。 - 引用[3]:讨论了join优化,特别是倾斜键的处理。Hive可以将倾斜键写入文件,并启动另一个job进行map join。 用户的问题是关于顺序:先group byjoin vs. 先joingroup by。我需要比较这两种顺序的性能。 关键点在Hive的执行计划和数据倾斜: - 在Hive中,group by操作通常涉及shuffle阶段,将相同key的数据发送到同一个reducer。 - join操作也涉及shuffle,尤其是当join键不是分区键时。 - 数据倾斜会导致某些reducer处理大量数据,拖慢整个作业。 效率对比: 1. **先group byjoin**: - 优点:如果group by减少了数据量(例如,聚合后行数变少),那么join操作处理的数据会更少,可能减少shuffle的数据量。 - 缺点:如果group by导致数据倾斜,join时可能放大问题。 - 引用[1]中提到group by可能引发数据倾斜,需要优化。 2. **先joingroup by**: - 优点:join可能会过滤或合并数据,然后group by处理聚合。 - 缺点:如果join后数据量很大,group by的shuffle阶段可能更慢;join本身也可能有倾斜问题。 - 引用[3]中提到join是数据倾斜的重灾区,Hive有机制处理倾斜键。 一般优化原则: - **减少数据量尽早**:在数据处理管道中,尽可能早地减少数据量(例如,通过filter或aggregate),以降低后续操作的开销。 - 因此,如果group by能显著减少数据大小,先做group by可能更高效。 - **避免不必要的shuffle**:减少shuffle操作的次数和数据量。 - **数据倾斜处理**:无论顺序,都需要考虑数据倾斜。引用中提到使用配置项,但更推荐在SQL层面优化。 在Hive中,顺序可能影响执行计划: - Hive的优化器(CBO)会尝试重写查询以优化性能。 - 但用户指定了SQL顺序,Hive可能不改变操作顺序,除非有优化提示。 根据引用: - 引用[1]:group by时处理倾斜很重要。 - 引用[2]:提到distribute by可以控制数据分发。 - 引用[3]:join优化,处理倾斜键。 所以,对于用户的问题: - **先group byjoin**:如果group by键的选择性好(即能有效聚合),减少了join的数据量,效率更高。但如果group by键有倾斜,问题更大。 - **先joingroup by**:如果join过滤了大量数据,然后group by处理较少数据,可能更好。但join可能引入倾斜。 推荐最佳实践: - 通常,**先group by以减少数据量再进行join**是更优的,因为join操作成本更高。 - 但需要监控数据分布,处理倾斜。 引用中提到优化方法: - 使用hive.groupby.skewindata来处理group by倾斜。 - 对于join,使用hive.skewjoin.key等来处理倾斜键。 - 在SQL层面,优化查询,如使用distribute by等。 回答结构: - 解释两种顺序。 - 比较效率,基于数据量和倾斜。 - 给出一般建议。 - 引用相关引用内容(添加引用标识)。 - 最后生成相关问题。 生成相关问题:基于用户查询,问题应围绕Hive优化。 完整回答: - 概述问题。 - 详细比较两种顺序。 - 提供优化建议。 - 结尾生成问题。 </think>### Hive中先group byjoin on与先join on再group by的效率对比 在Hive中,查询顺序(先`GROUP BY`再`JOIN ON` vs. 先`JOIN ON`再`GROUP BY`)会显著影响执行效率和性能,主要取决于数据量、数据倾斜情况以及Hive的执行计划优化。以下基于Hive的工作原理(如MapReduce阶段)和提供的引用内容,详细对比这两种顺序的效率。 #### 1. **效率对比分析** - **先`GROUP BY`再`JOIN ON`**: - **优点**:如果`GROUP BY`操作能有效减少数据量(例如,聚合后行数大幅减少),后续`JOIN`处理的输入数据会更小,从而降低Shuffle阶段的数据传输量和计算开销。这在数据分布均匀时效率更高,因为`JOIN`操作的代价通常比`GROUP BY`更高(涉及多表匹配)。 - **缺点**:如果`GROUP BY`键存在数据倾斜(如某些key对应的数据量过大),会导致部分Reducer负载过高,拖慢整个作业。Hive提供了`hive.groupby.skewindata`配置项(默认false)来缓解,但它通过启动两个MR job实现,会增加额外开销[^1]。在数据倾斜严重时,效率可能不如预期。 - **适用场景**:当聚合操作能显著压缩数据(如统计每个用户的订单数后,再与其他表join),且数据倾斜风险较低。 - **先`JOIN ON`再`GROUP BY`**: - **优点**:`JOIN`操作可能先过滤或合并数据(例如,通过WHERE条件或小表map join),之后再聚合,避免了在大型数据集上直接`GROUP BY`的开销。这在join键分布均匀时效果较好,尤其当join能利用分区或桶优化。 - **缺点**:`JOIN`本身是数据倾斜的“重灾区”(如某些join key关联大量行),可能导致Shuffle数据膨胀,后续`GROUP BY`处理更大数据集,增加Reducer压力。Hive支持`hive.skewjoin.key`阈值(默认100,000)来拆分倾斜键到临时文件,但这也涉及额外的job和资源消耗[^3]。如果join后数据量未减少,整体效率可能更低。 - **适用场景**:当join表较小或join操作能有效缩小数据集(如过滤无效记录),且group by键的基数较小。 **效率总结**: - **一般原则**:在Hive中,"尽早减少数据量"是优化核心。因此,如果`GROUP BY`能显著降低数据规模(如减少50%以上),先`GROUP BY`再`JOIN`通常更高效,否则先`JOIN`再`GROUP BY`可能更优。 - **数据倾斜影响**:无论顺序如何,数据倾斜都是关键瓶颈。引用中提到,单纯依赖Hive配置(如`hive.groupby.skewindata`)常不足以根本解决问题,需结合SQL层面优化[^1][^3]。 - **性能实测**:通过Hive的`EXPLAIN`命令分析执行计划,观察Shuffle数据量和Reducer数量。实际测试中,先`GROUP BY`再`JOIN`在低倾斜场景下可能快20%~50%,但在高倾斜时反而慢。 #### 2. **优化建议** 基于引用内容,提升效率的策略包括: - **处理数据倾斜**: - 对于`GROUP BY`,使用`distribute by`结合`sort by`控制数据分发(如`SELECT ... GROUP BY key DISTRIBUTE BY key SORT BY key`),避免单一Reducer过载[^2]。 - 对于`JOIN`,在SQL中手动拆分倾斜键(如将大key单独处理),或设置`hive.skewjoin.mapjoin.map.tasks`调整Mapper数量[^3]。 - **减少Shuffle开销**: - 在`GROUP BY`前添加过滤条件(如`WHERE`),或使用`map-side aggregation`(开启`hive.map.aggr=true`)。 - 对于`JOIN`,优先使用`MAPJOIN`处理小表(如`/*+ MAPJOIN(small_table) */`),避免Shuffle。 - **配置优化**: - 开启`hive.groupby.skewindata`并监控效果,但不要过度依赖[^1]。 - 调整`hive.exec.reducers.bytes.per.reducer`控制Reducer数据量。 - **查询重写**:Hive的Cost-Based Optimizer(CBO)可能自动重写顺序,但如果性能不佳,可以强制指定操作次序。 #### 3. **实际案例** 假设查询用户订单统计: - **高效写法(先`GROUP BY`再`JOIN`)**: ```sql SELECT a.user_id, COUNT(*), b.user_name FROM ( SELECT user_id, COUNT(*) AS order_count FROM orders GROUP BY user_id -- 先聚合减少数据 ) a JOIN users b ON a.user_id = b.user_id; ``` 如果`orders`表有上亿行,但`user_id`只有几千个,此写法减少join数据量,提升效率。 - **低效场景(先`JOIN`再`GROUP BY`)**: ```sql SELECT a.user_id, COUNT(*), b.user_name FROM orders a JOIN users b ON a.user_id = b.user_id -- 可能放大数据 GROUP BY a.user_id, b.user_name; ``` 如果`join`后数据未过滤,且`user_id`有倾斜,性能可能下降。 最终,优化时应结合数据采样(如`ANALYZE TABLE`)和测试。Hive文档建议:在数据倾斜可控时优先压缩数据量;在join复杂时优先过滤[^1][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值