前文
Hive的本质是MapReduce,MapReduce中如何排序的??
MapReduce分为几种:
1.全排序order By: 结果只有一个(也就是只有一个分区),所有的数据整体有序.
2.部分排 序sort By: 结果有多个(相当于有多个分区),每个分区内部有序的.
3.二次排序: 在排序时,比较的条件有多个,比如说按总流量排序,总流量相等就按上行流量排序.
注意:
排序是在reduce之前就已经排好序了,排序是shuffle阶段的主要工作.然后让Reduce方便接下来的处理
准备数据
准备 emp.txt到/root/soft 目录下面,
7369 SMITH CLERK 7902 1980-12-17 800.00 20
7499 ALLEN SALESMAN 7698 1981-2-20 1600.00 300.00 30
7521 WARD SALESMAN 7698 1981-2-22 1250.00 500.00 30
7566 JONES MANAGER 7839 1981-4-2 2975.00 20
7654 MARTIN SALESMAN 7698 1981-9-28 1250.00 1400.00 30
7698 BLAKE MANAGER 7839 1981-5-1 2850.00 30
7782 CLARK MANAGER 7839 1981-6-9 2450.00 10
7788 SCOTT ANALYST 7566 1987-4-19 3000.00 20
7839 KING PRESIDENT 1981-11-17 5000.00 10
7844 TURNER SALESMAN 7698 1981-9-8 1500.00 0.00 30
7876 ADAMS CLERK 7788 1987-5-23 1100.00 20
7900 JAMES CLERK 7698 1981-12-3 950.00 30
7902 FORD ANALYST 7566 1981-12-3 3000.00 20
7934 MILLER CLERK 7782 1982-1-23 1300.00 10
创建表
注意, 分隔符不要写错了,不然导入数据会导入不进来.
sql:
create external table if not exists emp
(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int
) row format delimited fields terminated by '\t';
select *
from emp;
导入数据
如果导入数据失败,看看是不是分隔符弄错了,,我曾经就出现过这个错误,弄了20分钟找不到问题,最后发现创建表的语句 \t 我给写成了 /t … = =. 结果就出现导入失败的情况.
sql:
load data local inpath '/root/soft/emp.txt'
into table emp;
查看导入的结果
sql
select *
from emp;
Order By全排序
Order By:全局排序,一个ReducerTask,也就是对所有的数据进行排序.如果多个Reduce的话是无用的.
使用 ORDER BY 子句排序
ASC(ascend): 升序(默认)
DESC(descend): 降序
案例
使用上和MySQL的order by没啥区别
-- 查询员工信息按工资升序排列
hive (default)> select * from emp order by sal;
-- 查询员工信息按工资降序排列
hive (default)> select * from emp order by sal desc;
Sort By 每个MapReduce内部排序
使用Sort By 的话, 需要将ReduceTask最少要大于1,不然没效果. 一个ReduceTask就是一个分区,五个ReduceTask就是五个分区.
每个Reducer内部进行排序,对全局结果集来说不是排序。
操作说明
设置Reduce个数
sql:
-- 1.设置reduce个数
set mapreduce.job.reduces=3;
-- 2.查看设置reduce个数
set mapreduce.job.reduces;
--3.根据部门编号降序查看员工信息
select *
from emp sort by empno desc;
这样执行完了你会发现数据都是乱的,没有什么效果..
需要将数据导出到文件里面才能看到效果
sql
-- 将查询的语句导入到指定文件里面
insert overwrite local directory '/root/soft/sortby-result'
row format delimited fields terminated by '\t'
select *
from emp sort by sal desc;
此时Linux的/root/soft下会生成一个sortby-result文件夹
为什么是三个???
因为启动了三个ReduceTask 任务
[root@zjj101 soft]# cd sortby-result/
[root@zjj101 sortby-result]# ls
000000_0 000001_0 000002_0
[root@zjj101 sortby-result]# pwd
/root/soft/sortby-result
[root@zjj101 sortby-result]#
依次查看这三个文件里面的内容
根据sal 降序排序,sal字段是从左往右数第六个字段, 你就能看到每个ReduceTask(分区)内部都是有序排列的了.
shell
[root@zjj101 sortby-result]# ls
000000_0 000001_0 000002_0
[root@zjj101 sortby-result]# cat 000000_0
7839 KING PRESIDENT \N 1981-11-17 5000.0 \N 10
7788 SCOTT ANALYST 7566 1987-4-19 3000.0 \N 20
7698 BLAKE MANAGER 7839 1981-5-1 2850.0 \N 30
7782 CLARK MANAGER 7839 1981-6-9 2450.0 \N 10
7844 TURNER SALESMAN 7698 1981-9-8 1500.0 0.0 30
7654 MARTIN SALESMAN 7698 1981-9-28 1250.0 1400.0 30
[root@zjj101 sortby-result]# cat 000001_0
7566 JONES MANAGER 7839 1981-4-2 2975.0 \N 20
7499 ALLEN SALESMAN 7698 1981-2-20 1600.0 300.0 30
7934 MILLER CLERK 7782 1982-1-23 1300.0 \N 10
7521 WARD SALESMAN 7698 1981-2-22 1250.0 500.0 30
7876 ADAMS CLERK 7788 1987-5-23 1100.0 \N 20
7900 JAMES CLERK 7698 1981-12-3 950.0 \N 30
[root@zjj101 sortby-result]# cat 000002_0
7902 FORD ANALYST 7566 1981-12-3 3000.0 \N 20
7369 SMITH CLERK 7902 1980-12-17 800.0 \N 20
[root@zjj101 sortby-result]#
Distribute By 分区排序
分区和排序都是在shuffle阶段完成,分区是在MapTask阶段的Shuffle完成, 排序是在MapTask完成,在ReduceTask也有完成.
分区是使用partition分区器来进行分区的,当你的ReduceTask的个数大于1的时候,先设置用户自己定义的分区器,如果没有的话,缺省使用hash分区器,hash分区器特点是只用key的hashCode来分区.
你在输入查询语句执行查询的时候,底层是经过了MapReduce程序,会给你输入的字段都封装成key和value,分区只是对key来分区.那么你不知道你哪些数据分散到哪个ReduceTask里面.
如果你只写sort by的话,那么就是随机分区.如果你希望自己定义使用哪个字段来分区,那么你就需要使用Distribute By字段,这个Distribute By是指定你按哪个字段分区的. Distribute By在全排序是没有意义的,因为全排序是只有一个ReduceTask,那么不管你key是什么的话,全都是0号分区,所以说Distribute By只有结合部分排序才有意义的.所以一般情况下Distribute By 是结合sort by 来使用的
注意,Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前。
对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。
案例
先按照部门编号分区,再按照员工编号降序排序。
sql:
set mapreduce.job.reduces=3;
insert overwrite local directory '/root/soft/sortby-result'
row format delimited fields terminated by '\t'
select *
from emp distribute by deptno
sort by empno desc;
注意: overwrite 这个是自动删除指定的目录.
执行完了之后会生成三个文件,因为是三个ReduceTask
仔细观察,部门号是最右面的那个,是按照部门号排序的,默认是hash分区器,然后每个ReduceTask内部是按照员工编号排序的,员工编号是最左面的一个字段.
[root@zjj101 soft]# cd sortby-result/
[root@zjj101 sortby-result]# ls
000000_0 000001_0 000002_0
[root@zjj101 sortby-result]# cat 000000_0
7900 JAMES CLERK 7698 1981-12-3 950.0 \N 30
7844 TURNER SALESMAN 7698 1981-9-8 1500.0 0.0 30
7698 BLAKE MANAGER 7839 1981-5-1 2850.0 \N 30
7654 MARTIN SALESMAN 7698 1981-9-28 1250.0 1400.0 30
7521 WARD SALESMAN 7698 1981-2-22 1250.0 500.0 30
7499 ALLEN SALESMAN 7698 1981-2-20 1600.0 300.0 30
[root@zjj101 sortby-result]# cat 000001_0
7934 MILLER CLERK 7782 1982-1-23 1300.0 \N 10
7839 KING PRESIDENT \N 1981-11-17 5000.0 \N 10
7782 CLARK MANAGER 7839 1981-6-9 2450.0 \N 10
[root@zjj101 sortby-result]# cat 000002_0
7902 FORD ANALYST 7566 1981-12-3 3000.0 \N 20
7876 ADAMS CLERK 7788 1987-5-23 1100.0 \N 20
7788 SCOTT ANALYST 7566 1987-4-19 3000.0 \N 20
7566 JONES MANAGER 7839 1981-4-2 2975.0 \N 20
7369 SMITH CLERK 7902 1980-12-17 800.0 \N 20
[root@zjj101 sortby-result]#
Cluster By
当distribute by和sorts by字段相同时,可以使用cluster by方式说白了就是如果你分区的字段和排序的字段一致的话,可以简写为Cluster By
cluster by就是distribute by+sort by的组合,但是只能默认升序。
cluster by除了具有distribute by的功能外还兼具sort by的功能。但是排序只能是升序排序,不能指定排序规则为ASC或者DESC。
以下两种写法等价,我就不演示了..
select * from emp cluster by deptno;
select * from emp distribute by deptno sort by deptno;