Hive - 快速入门教程7(排序语句、分组和去重)
在 MySQL 中,能实现排序功能的只有 ORDER BY 语句。在 Hive 中,除了 ORDER BY 外,还有 SORT BY、DISTRIBUTE BY 和 CLUSTER BY。它们区别如下:
(2)接着我们使用 SORT BY 实现局部排序功能:
(3)结果如下,可以发现数据没有全局排序,因为这个任务中有多个 Reduce:
(2)DISTRIBUTE BY 经常和 SORT BY 结合使用,可以实现“先对数据分区,再排序”。
(2)下面看一下单独使用 DISTRIBUTE BY 的效果,可以看到由于我们设置了两个分区,根据 id 分区后也就是 id 是奇数的在一个分区,偶数的在一个分区:
(3)下面是 DISTRIBUTE BY 结合 SORT BY 实现分区内的排序,默认是升序,可以通过 DESC 来设置倒序。
(2)CLUSTER BY 指定的列只能是升序,不能手工指定 ASC 或者 DESC。如果有特珠需求则不能使用这种简化形式。
(2)然后使用 CLUSTER BY 实现分区内的排序:
(2)但是二者的性能有差别:
- ORDER BY:全局排序
- SORT BY:局都排序
- DISTRIBUTE BY:只负责分区
- CLUSTER BY:等于 DISTRIBUTE BY + SORT BY
下面我将通过样例详细介绍各个排序。
一、ORDER BY(全局排序)
1,基本介绍
(1)Hive 中的 ORDER BY 和 MySQL 中的 ORDER BY 语句的作用是一样的,会对查询的结果做一次全局排序。
(2)使用 ORDER BY 语句时,底层生成的 Reduce 任务只有一个。
2,使用样例
下面样例根据 score 列值进行全局倒序排序:
select * from course order by score desc;
二、SORT BY(局都排序)
1,基本介绍
(1)SORT BY 语句用于实现局部排序,而不是像 ORDER BY 那样对整个数据集进行排序。这有助于减小排序的数据量,提高性能
(2)对于多个 Reduce 任务,SORT BY 只能保证每个 Reducer 任务内部的数据是有序的。
2,使用样例
(1)首先我们动态设置 Reduce 任务数量为 2:
set mapreduce.job.reduces=2;
(2)接着我们使用 SORT BY 实现局部排序功能:
select * from course sort by score desc;
(3)结果如下,可以发现数据没有全局排序,因为这个任务中有多个 Reduce:
三、DISTRIBUTE BY(分区)
1,基本介绍
(1)DISTRIBUTE BY 用于控制 Map 的输出如何被划分到 Reduce 中,只会根据指定的字段对数据进行分区,但是不会排序。(2)DISTRIBUTE BY 经常和 SORT BY 结合使用,可以实现“先对数据分区,再排序”。
注意:DISTRIBUTE BY 和 SORT BY 结合使用时,DISTRIBUTE BY 必须要写在 SORT BY 之前。
2,使用样例
(1)首先我们动态设置 Reduce 任务数量为 2:
set mapreduce.job.reduces=2;
(2)下面看一下单独使用 DISTRIBUTE BY 的效果,可以看到由于我们设置了两个分区,根据 id 分区后也就是 id 是奇数的在一个分区,偶数的在一个分区:
select * from course distribute by id;
(3)下面是 DISTRIBUTE BY 结合 SORT BY 实现分区内的排序,默认是升序,可以通过 DESC 来设置倒序。
select * from course distribute by id sort by score desc;
四、CLUSTER BY(综合排序)
1,基本介绍
(1)CLUSTER BY 等于 DISTRIBUTE BY + SORT BY 的简写形式,即 CLUSTER BY id = DISTRIBUTE BY id + SORT BY id。(2)CLUSTER BY 指定的列只能是升序,不能手工指定 ASC 或者 DESC。如果有特珠需求则不能使用这种简化形式。
2,使用样例
(1)首先我们动态设置 Reduce 任务数量为 2:
set mapreduce.job.reduces=2;
(2)然后使用 CLUSTER BY 实现分区内的排序:
select * from course cluster by id;
五、分组和去重
1,函数说明
- GROUP BY :对数据按照指定字段进行分组
- DISTINCT:对数据中指定字段的重复值进行去重
2,使用样例
(1)下面两个语句都可以统计出订单表中用户的数量:
select count(distinct name) from order select count(tmp.name) from (select name from order group by name) tmp
(2)但是二者的性能有差别:
- 第一种:使用 distinct 会将所有的 name 都 shuffle 到一个 reducer 里面,性能较低
- 第二种:先对 name 分组,因为分组的同时其实就是去重,此时是可以并行计算的,然后再计算 count 即可,性能高。