Hive - 排序详解(order/sort/cluster by)

491 阅读3分钟

1. 全局排序 - order by

order by 会对全局的数据进行排序,也就是说,排序只会在一个 reduce 中进行,因此,如果遇到数据量非常大的时候,单纯使用 order by 并不是最佳的选择,因为它的执行效率会相对低下。

但是,在日常的开发中,order by 仍然是我们最常用排序方法。

需要注意的是,在严格模式下(set hive.mapred.mode = strict),order by 必须要和 limit 一起用,否则是会报错的,当然,Hive 一般默认使用的是非严格模式(set hive.mapred.mode=nonstrict)

set hive.mapred.mode = strict;

select * from temp order by sort01
输出结果:报错

1.1 对列进行全局排序

  • 升序排序(默认):asc

  • 降序排序:desc

    with temp as( select 'c' as sort01,'c' as sort02 union all select 'b' as sort01,'b' as sort02 union all select 'd' as sort01,'d' as sort02 union all select 'a' as sort01,'a' as sort02 union all select 'a' as sort01,'b' as sort02 )

    select * from temp order by sort01 desc,sort02 asc 输出结果: sort01 sort02 d d c c b b a a a b

    select * from temp order by sort01 desc,sort02 desc 输出结果: sort01 sort02 d d c c
    b b a b a a

1.2 自定义全局排序 - order by decode(field,key01,value01,key02,value02,...),...

with temp as (
select 'a' as sort01
union all 
select 'b' as sort01
union all 
select 'c' as sorts
union all 
select 'd' as sorts
)

select sort01 from temp order by decode(sort01,'b','a','a','b') asc
输出结果:
sort01
b
a
c
d

select sort01 from temp order by decode(sort01,'c',1,'a',2,'b',3,'d',4) asc
输出结果:
c
a
b
d

2. 将数据分发到不同的 reduce - distribute by

distrubute by 可以控制map端输出结果的分发,distrubute by 所指定字段的相同数据会分发到同一个reduce 节点中处理,不同的数据分发到不同的reduce中,从而达到分发的效果。

distribute by 就类似于 MR 中的自定义分区(Partiton),它的分区规则是根据分区字段的 hash 值与 reduce 个数进行模除后,余数相同的分到一个分区中。

如下,按照部门编号进行分区:

set mapreduce.job.reduce=3;

select * from temp distribute by deptno

3. 局部排序 - sort by

当 reduce 的个数为 1 个时(设置 reduce 的个数:set mapred.reduce.tasks=1 或者 set mapreduce.job.reduce=1),sort by 的效果与order by 的效果基本是一样的,不同之处在于,order by 受严格模式所影响(set hive.mapred.mode = strict),而 sort by 是不受严格模式影响的。

当 reduce 的个数大于1个时,sort by 可以对每个 reduce 进行局部排序,并为每个 reduce 产生一个排序文件,但是不能保证全局有序。

在日常的开发中,我们需要控制某些特定的数据分发到哪个 reduce 中,并且在该 reduce 里先进行局部排序,因此,我们会把 distribute by 和 sort by 连用,同时要注意 distribute by 语句要写在 sort by 语句之前。

如下,按照部门编号进行分区,再按照员工的编号升序排序

set mapreduce.job.reduce=3;

select * from temp distribute by dept_no order by emp_no

4. cluster by

cluster by 只能是升序排序,不能指定排序规则为 asc 或者 desc。当查询语句中 cluster by 指定的字段与 distribute by 和 sort by 所指定的字段相同,并且排序规则为 asc 的时候,cluster by = distribute by + sort by

如下两个写法的效果是一样的:

select * from temp cluster by prdc_code
select * from temp distribute by prdc_code sort by prdc_code