一、优化

1.fetch抓取

一些HQL语句,可以不翻译为MR程序,而是使用FetchTask来运行,拉取数据!

启用了fetch抓取,可以节省某些HQL语句的查询效率!

默认fetch抓取的设置是开启的,为more

hive.fetch.task.conversion=more

一般不需要设置!

2.表的Join

2.1表Join的顺序

在hive中,不管是 大表 join 小表还是 小表 Join 大表,hive都可以自动优化!

2.2 大表之间的Join

在MR中ReduceJoin的原理:

Map阶段
①ReduceTask可以启动任意数量,必须保证关联字段相同的分到同一个区
关联字段相同的数据,才能分到同一个ReduceTask
②数据源有两种不同类型的文件,都使用同一个map处理逻辑!
因此在map()需要根据切片的来源,进行判断,从而进行不同的封装逻辑的选择!
③Mapper中封装数据的bean,应该可以覆盖不同类型文件中的所有字段
④需要在bean中打标记,标记bean封装的是哪个文件中的数据
只需要将order.txt中的数据进行替换后输出!
Reduce阶段
⑤在reduce()中,根据数据的标记进行分类
分为order.txt中的数据和pd.txt中的数据
⑥在cleanup()中,只讲order.txt中的数据,替换后写出
左外连接,如果左表A表中有大量的c字段的值为null的数据,如果不对null的数据进行过滤,此时会产生数据倾斜!

左外连接,如果左表A表中有大量的c字段的值为null的数据,如果不对null的数据进行过滤,此时会产生数据倾斜!

A left join B on A.c=B.c

大量的为null的字段的数据,分配到同一个区,这个区最终是会被一个Reducer处理,此时这个Reducer的负载较大!

2.2.1 空Key过滤

如果关联字段为null的数据,是不需要,可以对空Key进行过滤:

select n.* from (select * from nullidtable where id is not null ) n  left join ori o on n.id = o.id;

2.2.2 空key转换

以上情况,如果为null的字段不能过滤!此时需要对nullkey进行转换!

目的: 转换后null的key可以随机地分配到多个不同的区中,负载均衡

原则: 转换后,不能影响SQL原本查询的结果!

注意: 注意转换后的类型必须能否正确赋值给原先的数据类型!

举例:
注意:(因为id是int 类型,rand()的范围是[0,1),所以必须乘以100,再取整,上下取整都可以**,加负号是为了避免与另一张表有相同的id,影响原来的关联结果**。)

insert overwrite local directory '/home/user/join3' 
select n.* from nullidtable n full join ori o on 
case when n.id is null then -floor(rand()*100) else n.id end = o.id;

3.Group By优化

select deptno,count(*) from emp group by deptno;

统计每个部门的员工的个数!同一个部门的数据需要汇总到同一个ReduceTask!

按照deptno进行分区!

如果不开启Group by优化,此时默认使用一个Job来进行运算!此时如果某个部门的员工数量特别多,那么这个部门所在的区,就会发生数据倾斜,造成此区所负责的reduceTask负载不均衡!

如何优化?开启负载均衡配置:

hive.groupby.skewindata = true

此时在Group by时,一个Job会变为两个Job!第一个Job负责随机分区,按detpno进行分组,先进行聚合!

第二个Job再将第一个Job输出地数据,再按照deptno进行分区,进行最终的聚合!

举例:

deptno

name

10

jack

10

tom

20

marry

20

nick

10

jerry

第一个Job负责随机分区,按detpno进行分组,先进行聚合!

ReduceTask1:

deptno

name

10

jack

10

tom

20

marry

先进行聚合,以deptno作为分组(MR中的分组)的条件!

输出:(10,2),(20,1)

ReduceTask2:

deptno

name

20

nick

10

jerry

输出:(10,1),(20,1)

第二个Job再将第一个Job输出的数据,再按照deptno进行分区,进行最终的聚合!

ReduceTask1:(10,2)(10,1)----> (10,3)
ReduceTask2:(20,1)(20,1)----> (20,2)

4.动态分区

当向一个分区表插入数据时,必须指定要插入数据的分区信息!

insert into table 表名 partition(分区字段名=分区字段值),此种方式称为静态分区!

向哪个分区插入数据已知!

动态分区:在插入时,分区字段值根据要插入数据的某个字段动态生成!

示例:

创建一个和员工表类似的分区表,这个表以Job为分区字段

create external table if not exists default.emp_partition(
empno int,
ename string,
mgr int,
hiredate string, 
sal double, 
comm double,
deptno int)
Partitioned by(job string)
row format delimited fields terminated by '\t';

动态分区:

①开启允许进行动态分区

set hive.exec.dynamic.partition.mode=nonstrict

②分区列必须作为向表中插入数据的最后一列,注意顺序

insert into table emp_partition partition(job) select empno,ename,mgr,hiredate,sal,comm,deptno,job from emp;