hive中的join

多个表进行join的MapReducer任务的数量

根据最典型的学生课程表,由于学生和课程之间是多对多的关系,所以需要一张中间表stundet_course表进行关联

案例一:查询学生课程信息

select stu.* , c.* from student stu join student_course sc on student.sno = sc.sno join course c on sc.cno = c.cno

大多数情况下,hive会对每一对join连接对象启动一个MapReduce任务,这个例子中就应该是先执行一个mapreducer job 将表student与student_course 表进行连接,输出结果,再执行一个mapreducer job将该输出结果与course表进行连接,输出最终的结果。

案例二:查询学生的住宿地址和家庭地址信息

select stu.* , dorm.* ,home.* from student stu join dorm on student.sno = dorm.sno join home on stu.sno = home.sno

注意但是在这个例子中,得益于一个优化,因为这边的每一个join的on子句中都使用到了student.sno这个字段,在这种情况下,hive通过一个优化可以在同一个mapreducer中连接3个表
换句话说,当对3个或3个以上的表进行join连接的时候,如果每一个on子句都使用相同的连接键的话,那么只会产生一个mapreduce job。

join连接时表连接的顺序

hive进行连接的时候,会假定最后的一个表是最大的那个表,在对每一行记录进行连接操作的时候,它会先尝试将其他的表缓存起来,然后扫描最后的那张表进行计算,因此用户在连接的时候,需要保证连续查询中的表的大小是从左到右依次增加的。

map-side join

如果连接的表中有一张表是小表,那么完全可以将这张表存放在内存中,直接在map端进行join就可以了(可以在map端将大表与内存中的小表进行逐一匹配),从而省略掉了常规连接操作中所需要的reduce过程。
不过这样做需要进行一些配置:

set hive.auto.convert.join=true

此外还可以设置使用这个优化的小表的大小

#单位bytes
hive.mapjoin.smalltable.filesize=25000000

不过需要注意的是,hive对于右外连接,左外连接不支持这个优化

left semi join

左半开连接:返回左边表的记录,其前提是对于右边表满足on语句中的判定条件,这是一个特殊的inner join

因为hive不支持in关键字,所以只用这个join进行达到这种相同的目的:

案例

得到住在学校的学生的信息

#在mysql中本来是这么写的,但是hive中不支持
select stu.* from student stu where stu.sno in (select sno from dorm) #hive中使用优化了的inner joinleft semi join进行操作 select stu.* from student stu left semi join dorm on dorm.sno = stu.sno

注意: 在select和where中不能出现右边表的任何字段。
原理: 对于左边表中的一条记录,在右边一旦找到一条,那么就会立刻停止对右表的扫描,从而效率比inner join要高

你可能感兴趣的:(JOIN,hive,mapside,left-semi)