目录
- 两表join
- 等值连接:inner join
- 外连接:left join 、right join
- 实现非等值连接
- 多表join
- 三表inner join
- 计算新增用户
- 计算每个国家记录数的百分比
- 新建字典表用于join
- 要避免的查询操作
- full outer join
- union的使用
- map端的join
Hive Join
hive只支持等值连接,外连接。
hive不支持非相等的join条件(通过其他方式实现,如left outer join),因为它很难在map/reduce job实现这样的条件。
hive可以join两个以上的表。
两表join
建表导入数据
-- 创建表test_a
CREATE TABLE test_a(
id int,
name string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
-- 创建表test_b
CREATE TABLE test_b(
id int,
name string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
--创建表test_c
CREATE TABLE test_c(
id int,
name string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
--分别导入数据到三个表中
--test_a
1 a1
2 a2
4 a4
--test_b
1 b1
3 b3
4 b4
--test_c
1 c1
4 c4
5 c5
-- load数据
load data LOCAL INPATH '/home/user/d1/joindata/file1' overwrite into table test_a;
load data LOCAL INPATH '/home/user/d1/joindata/file2' overwrite into table test_b;
load data LOCAL INPATH '/home/user/d1/joindata/file3' overwrite into table test_c;
等值连接:inner join
select * from test_a a inner join test_b b on a.id=b.id;
Total MapReduce CPU Time Spent: 4 seconds 210 msec
OK
1 a1 1 b1
4 a4 4 b4
Time taken: 20.556 seconds, Fetched: 2 row(s)
外连接:left join 、right join
--left join
select a.*,b.* from test_a a
left join test_b b
on a.id=b.id;
Total MapReduce CPU Time Spent: 3 seconds 700 msec
OK
1 a1 1 b1
2 a2 NULL NULL
4 a4 4 b4
--right join
select a.*,b.* from test_a a
right join test_b b
on a.id=b.id;
Total MapReduce CPU Time Spent: 3 seconds 710 msec
OK
1 a1 1 b1
NULL NULL 3 b3
4 a4 4 b4
实现非等值连接
-- 查询test_a有,test_b没有,用 left join + is null
select * from test_a a left join test_b b on a.id = b.id where b.id is null;
Total MapReduce CPU Time Spent: 4 seconds 330 msec
OK
2 a2 NULL NULL
-- 查询test_a没有,test_b有,用 right join + is null
select * from test_a a right join test_b b on a.id = b.id where a.id is null;
Total MapReduce CPU Time Spent: 4 seconds 30 msec
OK
NULL NULL 3 b3
多表join
三表inner join
--三表inner join
select a.*,b.name,c.name from test_a a
inner join test_b b on a.id=b.id
inner join test_c c on b.id=c.id;
计算新增用户
查询1228 有而1117 没有的数据
select * from
(select * from uis_partition where dt='20141228') a
left join
(select * from uis_partition where dt='20141117') b
on a.aid = b.aid
where b.aid is null;
计算每个国家记录数的百分比
无关联字段时创造字段 自定义连接条件
round,默认取整,如果想精确,那就在后面加精确几位小数
select b.country,round((b.ct*100)/a.t,2) bfb from
(
-- 计算所有国家的用户数
select count(DISTINCT aid) t,'my' jc from user_install_status_orc
) a inner join
(
-- 计算每个国家的用户数
select country,count(DISTINCT aid) ct,'my' jc from user_install_status_orc GROUP BY country
-- 以自创的字段连接
) b on a.jc = b.jc;
新建字典表用于join
制作字典文件country_dict.dat
create table country_dict(
code string,
name string,
region string
);
加载数据
……
要避免的查询操作
--笛卡尔积的SQL
select * from test_a inner join test_b;
-- 设置hive的严格校验(建议 很麻烦 确实可以帮助我们进行数据上的查询失误)
set hive.mapred.mode=strict;
设置这个参数,可以限制以下情况:
1)限制执行可能形成笛卡尔积的SQL;
2)partition表使用时不加分区;
3)order by全局排序的时候不加limit的情况;
-- 取消严格校验模式
set hive.mapred.mode=nonstrict;
full outer join
包括两个表的join结果,(左边有,右边NULL union 右边有,左边NULL)
其结果等于left join union right join
做test_a 与 test_b 的full outer join
select a.*,b.*
from test_a a full outer join test_b b
on a.id=b.id;
Total MapReduce CPU Time Spent: 8 seconds 890 msec
OK
1 a1 1 b1
2 a2 NULL NULL
NULL NULL 3 b3
4 a4 4 b4
用hive shell 执行HQL
用于执行HQL语句,将语句的查询结果放到文件里。
#数据输出,及错误输出均输出到u1
nohup hive -e "use hainiu;select * from user_install_status_limit;" > ~/u1 2>&1 &
#数据输出到u3,错误日志输出到无底洞
nohup hive -e "use hainiu;set mapred.reduce.tasks=1;select * from user_install_status_limit;" 1> ~/u3 2> /dev/null &
#数据输出到u3,错误日志输出到err.log
nohup hive -e "use hainiu;set mapred.reduce.tasks=1;select * from user_install_status_limit;" 1> ~/u3 2> ~/err.log &
union的使用
用 left join union right join 实现 full outer join
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。
select a.id aid,a.name aname, b.id bid,b.name bname from test_a a left join test_b b on a.id=b.id
union
select a.id aid,a.name aname, b.id bid,b.name bname from test_a a right join test_b b on a.id=b.id;
Total MapReduce CPU Time Spent: 9 seconds 430 msec
OK
NULL NULL 3 b3
1 a1 1 b1
2 a2 NULL NULL
4 a4 4 b4
优化方法:
增加 reduce的数据处理能力 reduce数据处理的越快 HIVESQL的运行的就越快
增加reducer任务数量
set mapred.reduce.tasks=4;
设置reducer内存大小
set mapreduce.reduce.memory.mb=512;
set mapreduce.reduce.java.opts=-Xmx2048m;
在同一个sql中的不同的job是否可以同时运行
set hive.exec.parallel=true;
增加同一个sql允许并行任务的最大线程数
set hive.exec.parallel.thread.number=8;
map端的join
什么是MapJoin
? = semijoin
MapJoin顾名思义,就是在Map阶段进行表之间的连接。而不需要进入到Reduce阶段才进行连接。这样就节省了在Shuffle阶段时要进行的大量数据传输。从而起到了优化作业的作用。
MapJoin原理
即在map 端进行join,其原理是broadcast join,即把小表作为一个完整的驱动表来进行join操作。
通常情况下,要连接的各个表里面的数据会分布在不同的Map中进行处理。即同一个Key对应的Value可能存在不同的Map中。
这样就必须等到 Reduce中去连接。要使MapJoin能够顺利进行,那就必须满足这样的条件:
除了一份表的数据分布在不同的Map中外,其他连接的表的数据必须在每 个Map中有完整的拷贝。
MAPJION会把小表全部读入内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配,由于在map是进行了join操作,省去了reduce运行的效率也会高很多。
MapJoin适用的场景:
mapjoin的适用场景如关联操作中有一张表非常小,.不等值的链接操作。通过上面分析你会发现,并不是所有的场景都适合用MapJoin. 它通常会用在如下的一些情景:在二个要连接的表中,有一个很大,有一个很小,这个小表可以存放在内存中而不影响性能。这样我们就把小表文件复制到每一个Map任务的本地,再让Map把文件读到内存中待用。
Hive版本区别:
Hive内置提供的优化机制之一就包括MapJoin。
在Hive v0.7之前,需要给出MapJoin的指示,Hive才会提供MapJoin的优化。
Hive v0.7之后的版本已经不需要给出MapJoin的指示就进行优化。
它是通过如下配置参数来控制的:
-- 开启自动mapjoin
set hive.auto.convert.join=true;
hive 0.11之后,在表的大小符合设置时
-- 是否自动转换为mapjoin
hive.auto.convert.join.noconditionaltask=true
--是否将多个mapjoin合并为一个这个参数控制多大的表可以放进内存,默认值为10000000L(10M),该值表示可以被转换为哈希映射的表大小的总和。
hive.auto.convert.join.noconditionaltask.size=10000
--小表的最大文件大小,默认为25000000,即25M
hive.mapjoin.smalltable.filesize=25000000
默认会把join转换为map join
-- 忽略MAPJOIN标记 /*+ MAPJOIN(smalltable)*/
hive.ignore.mapjoin.hint=true
-- 开启自动mapjoin
hive.auto.convert.join=true
MAPJOIN配置参数 :
set hive.auto.convert.join=true; // 将小表刷入内存中,默认true
set hive.ignore.mapjoin.hint=true; // 是否忽略mapjoin hint 即mapjoin标记 默认true
set hive.mapjoin.smalltable.filesize=2500000; // 刷入内存表的大小(字节),根据自己的数据集加大
可以设置不开启
set hive.auto.convert.join=false;
set hive.ignore.mapjoin.hint=false;
在设置成false 或 true时,可以手动的 /*+ MAPJOIN(c) */
。
select /*+ MAPJOIN(c) */ * from user_install_status_other u inner join country_dict c on u.country=c.code where u.dt='20141228' limit 10;
set hive.auto.convert.join=true;
set hive.ignore.mapjoin.hint=true;
如果是自动mapjoin,在使用MAPJOIN时,需要注意:
1、LEFT OUTER JOIN的左表必须是大表;
2、RIGHT OUTER JOIN的右表必须是大表;
3、INNER JOIN左表或右表均可以作为大表;
4、FULL OUTER JOIN不能使用MAPJOIN;
5、MAPJOIN支持小表为子查询;
6、使用MAPJOIN时需要引用小表或是子查询时,需要引用别名;
7、在MAPJOIN中,可以使用不等值连接或者使用OR连接多个条件;
mapjoin里写的是小表,且left outer join时小表写在join的后面;
hive中使用mapjoin有时可以大大提高sql语句的执行效率。
其原理是:它会把小表全部读入内存中,在map的时候直接拿另外一张表的数据和内存中表的数据做匹配,进行join操作,这样省去了reduce。
在“关联操作中有一个表非常小,另一个表很大”的场景下,mapjoin就不会由于数据倾斜而导致某个reduce上落数据太多而失败;