Hive表连接的语法支持如下:

  1. join_table:
  2. table_reference JOIN table_factor [join_condition]
  3. | table_reference {LEFT|RIGHT|FULL} [OUTER] JOIN table_reference join_condition
  4. | table_reference LEFT SEMI JOIN table_reference join_condition
  5. | table_reference CROSS JOIN table_reference [join_condition] (as of Hive 0.10)
  6. table_reference:
  7. table_factor
  8. | join_table
  9. table_factor:
  10. tbl_name [alias]
  11. | table_subquery alias
  12. | ( table_references )
  13. join_condition:
  14. ON equality_expression ( AND equality_expression )*
  15. equality_expression:
  16. expression = expression

hive只支持等连接,外连接,左半连接。hive不支持非相等的join条件(通过其他方式实现,如left outer join),因为它很难在map/reduce job实现这样的条件。而且,hive可以join两个以上的表。

例子

写join查询时,有几个典型的点要考虑,如下:

等连接

只有等连接才允许

  1. SELECT a.* FROM a JOIN b ON (a.id = b.id)
  2. SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department = b.department)

这两个是合法的连接

  1. SELECT a.* FROM a JOIN b ON (a.id <> b.id)

这个是不允许的。

多表连接

同个查询,可以join两个以上的表

  1. SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)

join的缓存和任务转换

hive转换多表join时,如果每个表在join字句中,使用的都是同一个列,只会转换为一个单独的map/reduce。


SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)  

这个会转换为单独的map/reduce任务,只有b表的key1列在join被调用。

另一方面


SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)  

被转换为两个map/reduce任务,因为b的key1列在第一个join条件使用,而b表的key2列在第二个join条件使用。第一个map/reduce任务join a和b。第二个任务是第一个任务的结果join c。

在join的每个map/reduce阶段,序列中的最后一个表,当其他被缓存时,它会流到reducers。所以,reducers需要缓存join关键字的特定值组成的行,通过组织最大的表出现在序列的最后,有助于减少reducers的内存。

三个表,在同一个独立的map/reduce任务做join。a和b的key对应的特定值组成的行,会缓存在reducers的内存。然后reducers接受c的每一行,和缓存的每一行做join计算。

类似

  1. SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)

这里有两个map/reduce任务在join计算被调用。第一个是a和b做join,然后reducers缓存a的值,另一边,从流接收b的值。第二个阶段,reducers缓存第一个join的结果,另一边从流接收c的值。

在join的每个map/reduce阶段,通过关键字,可以指定哪个表从流接收。

  1. SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)

三个表的连接,会转换为一个map/reduce任务,reducer会把b和c的key的特定值缓存在内存里,然后从流接收a的每一行,和缓存的行做join。

join的结果

LEFT,RIGHT,FULL OUTER连接存在是为了提供ON语句在没有匹配时的更多控制。例如,这个查询:


SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)  

将会返回a的每一行。如果b.key等于a.key,输出将是a.val,b.val,如果a没有和b.key匹配,输出的行将是 a.val,NULL。如果b的行没有和a.key匹配上,将被抛弃。语法"FROM a LEFT OUTER JOIN b"必须写在一行,为了理解它如何工作——这个查询,a是b的左边,a的所有行会被保持;RIGHT OUTER JOIN将保持b的所有行, FULL OUTER JOIN将会保存a和b的所有行。OUTER JOIN语义应该符合标准的SQL规范。

join的过滤

Joins发生在where字句前,所以,如果要限制join的输出,需要写在where字句,否则写在JOIN字句。现在讨论的一个混乱的大点,就是分区表


SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)  
WHERE a.ds='2009-07-07' AND b.ds='2009-07-07'  

将会连接a和b,产生a.val和b.val的列表。WHERE字句,也可以引用join的输出列,然后过滤他们。

但是,无论何时JOIN的行找到a的key,但是找不到b的key时,b的所有列会置成NULL,包括ds列。这就是说,将过滤join输出的所有行,包括没有合法的b.key的行。然后你会在LEFT OUTER的要求扑空。

也就是说,如果你在WHERE字句引用b的任何列,LEFT OUTER的部分join结果是不相关的。所以,当外连接时,使用这个语句


SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key AND b.ds='2009-07-07' AND a.ds='2009-07-07'  

join的输出会预先过滤,然后你不用对有a.key而没有b.key的行做过滤。RIGHT和FULL join也是一样的逻辑。

join的顺序

join是不可替换的,连接是从左到右,不管是LEFT或RIGHT join。


SELECT a.val1, a.val2, b.val, c.val  
FROM a  
JOIN b ON (a.key = b.key)  
LEFT OUTER JOIN c ON (a.key = c.key)  

首先,连接a和b,扔掉a和b中没有匹配的key的行。结果表再连接c。这提供了直观的结果,如果有一个键都存在于A和C,但不是B:完整行(包括 a.val1,a.val2,a.key)会在"a jOIN b"步骤,被丢弃,因为它不在b中。结果没有a.key,所以当它和c做LEFT OUTER JOIN,c.val也无法做到,因为没有c.key匹配a.key(因为a的行都被移除了)。类似的,RIGHT OUTER JOIN(替换为LEFT),我们最终会更怪的效果,NULL, NULL, NULL, c.val。因为尽管指定了join
key是a.key=c.key,我们已经在第一个JOIN丢弃了不匹配的a的所有行。

为了达到更直观的效果,相反,我们应该从


FROM c LEFT OUTER JOIN a ON (c.key = a.key) LEFT OUTER JOIN b ON (c.key = b.key).  

LEFT SEMI JOIN实现了相关的IN / EXISTS的子查询语义的有效途径。由于Hive目前不支持IN / EXISTS的子查询,所以你可以用 LEFT SEMI JOIN 重写你的子查询语句。LEFT SEMI JOIN 的限制是, JOIN 子句中右边的表只能在 ON 子句中设置过滤条件,在 WHERE 子句、SELECT 子句或其他地方过滤都不行。


SELECT a.key, a.value FROM a WHERE a.key in (SELECT b.key FROM B);  

可以重写为


SELECT a.key, a.val FROM a LEFT SEMI JOIN b on (a.key = b.key)  

mapjoin

但如果所有被连接的表是小表,join可以被转换为只有一个map任务。查询是

SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a join b on a.key = b.key

不需要reducer。对于每一个mapper,A和B已经被完全读出。限制是a FULL/RIGHT OUTER JOIN b不能使用。

如果表在join的列已经分桶了,其中一张表的桶的数量,是另一个表的桶的数量的整倍,那么两者可以做桶的连接。如果A有4个桶,表B有4个桶,下面的连接:

  1. SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a join b on a.key = b.key

只能在mapper工作。为了为A的每个mapper完整抽取B。对于上面的查询,mapper处理A的桶1,只会抽取B的桶1,这不是默认行为,要使用以下参数:

  1. set hive.optimize.bucketmapjoin = true;

如果表在join的列经过排序,分桶,而且他们有相同数量的桶,可以使用排序-合并 join。每个mapper,相关的桶会做连接。如果A和B有4个桶,

  1. SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM A a join B b on a.key = b.key

只能在mapper使用。使用A的桶的mapper,也会遍历B相关的桶。这个不是默认行为,需要配置以下参数:

  1. set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
  2. set hive.optimize.bucketmapjoin = true;
  3. set hive.optimize.bucketmapjoin.sortedmerge = true;

翻译自 https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Joins

Hive Joins 用法与操作的更多相关文章

  1. hive执行结果moveTask操作失败

    hive执行结果moveTask操作失败 Apache Hive 2.1.0 ,在执行"INSERT OVERWRITE TABLE ...... select "或者 " ...

  2. Hive学习(三)Hive的Java客户端操作

    Hive的Java客户端操作分为JDBC和Thrifit Client,首先启动Hive远程服务: hive --service hiveserver 一.JDBC 在MyEclipse中首先创建连接 ...

  3. 第3节 hive高级用法:16、17、18

    第3节 hive高级用法:16.hive当中常用的几种数据存储格式对比:17.存储方式与压缩格式相结合:18.总结 hive当中的数据存储格式: 行式存储:textFile sequenceFile ...

  4. Hive DDL、DML操作

    • 一.DDL操作(数据定义语言)包括:Create.Alter.Show.Drop等. • create database- 创建新数据库 • alter database - 修改数据库 • dr ...

  5. HIVE的sql语句操作

    Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在hadoop 分布式文件系统中的数据,可以将结构 化的数据文件映射为一张数据库表,并提供完整的SQL查 ...

  6. 利用SparkSQL(java版)将离线数据或实时流数据写入hive的用法及坑点

    1. 通常利用SparkSQL将离线或实时流数据的SparkRDD数据写入Hive,一般有两种方法.第一种是利用org.apache.spark.sql.types.StructType和org.ap ...

  7. Hive[5] HiveQL 数据操作

    5.1 向管理表中装载数据   Hive 没有行级别的数据插入更新和删除操作,那么往表中装载数据的唯一途径就是使用一种“大量”的数据装载操作,或者通过其他方式仅仅将文件写入到正确的目录下:   LOA ...

  8. Hive的用法

    1.Hive是Hadoop的一个子项目 利用MapReduce编程技术,实现了部分SQL语句.而且还提供SQL的编程接口.Hive推进Hadoop在数据仓库方面的发展. Hive是一个基于Hadoop ...

  9. Hive DDL及DML操作

    一.修改表 增加/删除分区 语法结构 ALTER TABLE table_name ADD [IF NOT EXISTS] partition_spec [ LOCATION 'location1' ...

随机推荐

  1. mysql设置有外键的主键自增及其他

    有外键的主键设置自增. ; ALTER TABLE `<table>` MODIFY COLUMN `id` ) NOT NULL AUTO_INCREMENT FIRST; 创建数据库, ...

  2. [原创]java WEB学习笔记36:Java Bean 概述,及在JSP 中的使用,原理

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  3. CSS3制作分步注册表单

    这个DEMO是使用CSS3制作的一个分步注册表单,每个input对应的是每一步,在表单得到焦点时,对应的step也会进行对应的改变.不过这个效果是使用js代码来实现,但整个表单的外观是由CSS3来完成 ...

  4. BZOJ 4199 [Noi2015]品酒大会:后缀数组 + 并查集

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4199 题意: 给你一个长度为n的字符串s,和一个长为n的数组v. 对于每个整数r∈[0,n ...

  5. 仿联想商城laravel实战---7、lavarel中如何给用户发送邮件

    仿联想商城laravel实战---7.lavarel中如何给用户发送邮件 一.总结 一句话总结: 设置邮件服务器,比如163邮箱 lavarel中配置邮件服务,在.env中 控制器中使用Mail对象发 ...

  6. 一 Django框架介绍——用pycharm创建Django项目

    Django框架介绍 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的软件设计模式,即模型M,视图V和控制器C.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内 ...

  7. poj-2478 Farey Sequence(dp,欧拉函数)

    题目链接: Farey Sequence Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14230   Accepted:  ...

  8. Android基于socket的群聊程序

    在网上看了好多,但是感觉不是太简单就是只能单独聊,所以就自己写了个可以群聊的,直接上代码了 一.服务器端 这里用的MyEclipse作为服务器端 MyServerScoket.java package ...

  9. BZOJ5324 JXOI2018 守卫

    传送门 这是我见过的为数不多的良心九怜题之一 题目大意 给定一段$n$个点构成的折线,第$i$个折点的坐标是$(i,h_i)$,你可以在$i$点放置一个视野,定义$i$能看到$j$当且仅当$i$处有视 ...

  10. 设置Suse linux 用户远程登录超时时间

    执行  # echo "export TMOUT=900"  >>  /etc/profile 查询设置结果: # cat /etc/profile|grep TMOU ...