Skip to main content

排序

全局排序(order by)

  • order by 子句出现在select语句的结尾;
  • order by子句对最终的结果进行排序;
  • 默认使用升序(ASC);可以使用DESC,跟在字段名之后表示降序;

ORDER BY执行全局排序,只有一个reduce;

-- 普通排序
select * from emp order by deptno;
-- 按别名排序
select empno, ename, job, mgr, sal + nvl(comm, 0) salcomm,
deptno
from emp
order by salcomm desc;
-- 多列排序
select empno, ename, job, mgr, sal + nvl(comm, 0) salcomm,
deptno
from emp
order by deptno, salcomm desc;

每个MR内部排序(sort by)

  • 对于大规模数据而言order by效率低;
  • 在很多业务场景,我们并不需要全局有序的数据,此时可以使用sort by;
  • sort by为每个reduce产生一个排序文件,在reduce内部进行排序,得到局部有序的 结果;
-- 设置reduce个数
set mapreduce.job.reduces=2;
-- 按照工资降序查看员工信息
select * from emp sort by sal desc;
-- 将查询结果导入到文件中(按照工资降序)。生成两个输出文件,每个文件内部数据
按工资降序排列
insert overwrite local directory '/home/hadoop/output/sortsal'
select * from emp sort by sal desc;

分区排序(distribute by)

  • distribute by 将特定的行发送到特定的reducer中,便于后继的聚合 与 排序操作;
  • distribute by 类似于MR中的分区操作,可以结合sort by操作,使分区数据有序;
  • distribute by 要写在sort by之前;
-- 启动2个reducer task;先按 deptno 分区,在分区内按 sal+comm 排序
set mapreduce.job.reduces=2;
-- 将结果输出到文件,观察输出结果
insert overwrite local directory '/home/hadoop/output/distBy'
select empno, ename, job, deptno, sal + nvl(comm, 0) salcomm
from emp
distribute by deptno
sort by salcomm desc;
-- 上例中,数据被分到了统一区,看不出分区的结果
-- 将数据分到3个区中,每个分区都有数据
set mapreduce.job.reduces=3;
insert overwrite local directory '/home/hadoop/output/distBy1'
select empno, ename, job, deptno, sal + nvl(comm, 0) salcomm
from emp
distribute by deptno
sort by salcomm desc;

Cluster By

  • 当distribute by 与 sort by是同一个字段时,可使用cluster by简化语法;
  • cluster by 只能是升序,不能指定排序规则;
-- 语法上是等价的
select * from emp distribute by deptno sort by deptno;
select * from emp cluster by deptno;

排序小结

  • order by。执行全局排序,效率低。生产环境中慎用
  • sort by。使数据局部有序(在reduce内部有序)
  • distribute by。按照指定的条件将数据分组,常与sort by联用,使数据局部有序
  • cluster by。当distribute by 与 sort by是同一个字段时,可使用cluster by简化语法