Hive支持连接查询,但有一些条件必须遵守,比如只支持相等查询,其它查询如不等式查询则不支持,还支持外连接,左半连接查询。另外Hive支持多于两个表以上的连接查询。下面为Hive连接查询的语法:
join_table: table_reference JOIN table_factor [join_condition] | table_reference {LEFT|RIGHT|FULL} [OUTER] JOIN table_reference join_condition | table_reference LEFT SEMI JOIN table_reference join_condition | table_reference CROSS JOIN table_reference [join_condition] (as of Hive 0.10) table_reference: table_factor | join_table table_factor: tbl_name [alias] | table_subquery alias | ( table_references ) join_condition: ON equality_expression ( AND equality_expression )* equality_expression: expression = expression上面的语法仅列出了连接查询的连接部分,至于查询部分可以参考SELECT语法格式。或许很多人在这样的语法面前都失掉了一半耐心,其实该语法很简单,可以理解为四种连接查询,分别为相等连接查询、外连接查询、左半连接查询和交叉连接(笛卡尔积)查询。即使这样还是有很多人不喜欢这么复杂的语法(包括本人)而更喜欢隐式连接查询,即FROM关键字后面跟着用逗号分隔的表明而省略掉join关键字,幸好Hive-0.13.0提供了这样的支持,如:
SELECT * FROM table1 t1, table2 t2, table3 t3 WHERE t1.id = t2.id AND t2.id = t3.id AND t1.zipcode = '02535';
下面通过一些列子对连接查询的某些特性进行学习。
//有效的连接查询,相等连接查询 SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department = b.department) //无效的连接查询,Hive不支持不等连接查询 SELECT a.* FROM a JOIN b ON (a.id <> b.id)
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
//由于jion子句中使用了表b的key1列,该查询转换为一个作业 SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1) //由于表b的key1列用在第一个jion子句中,key2列用在第二个jion子句中,该查询被转换为两个作业,第一个作业执行表a和b的连接查询,第二个作业将第一个作业的结果与第二个jion子句进行连接查询 SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
//下面的查询中,从a和b中满足条件的行中提取a.val和b.val,并缓存在reducers的内存中,对于从c中提取的每行记录,与缓存中的行进行连接计算 SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1) //下面的查询包含两个作业,第一个作业缓存a的值,将b的值以流的方式通过reducers,第二个作业缓存结果,并将c的值以流的方式通过reducers。 SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
//下面的查询中b.val和c.val缓存在reducers的内存中,对于从a中提取的每行记录,与缓存中的行进行连接计算。如果省略STREAMTABLE提示,jion中最右边的表被流处理 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)
SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)
该查询将返回a中的所有行,当a.key=b.key时返回a.val,b.val,没有对应的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中的所有行。
//ds为分区列 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中发现key而在b中没有发现key时,b中的列将为null,包括分区列ds,也就是将会过滤掉连接查询输出中没有有效b.key的列,或者说左外连接与WHERE子句中引用的b中的任何列无关。相反下面的语句将会提前根据条件过滤:
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')
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,丢掉所有不满足条件的记录,结果再与c进行左外连接。如果当key存在于a和c中但不在b中时,结果不是直观的。A中包含key的行丢弃掉,应为b中没有与key对应的行,这样结果将不包含key,再与c进行左外连接时将不包含c.val,该值将为null。如果是RIGHT OUTER JOIN的话,结果将为null,null,null,c.val,分析方法同分析左外连接一样。
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)
SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a join b on a.key = b.key
SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a join b on a.key = b.key
与对于a的每个mapper任务都读取整个b不同,只读取被要求的桶。对于上面的查询,处理a的桶1的mapper任务只读取b的桶1,但这不是默认行为,可以使用下面的参数进行配置管理:
hive.optimize.bucketmapjoin = true //默认值为false
hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;//默认为org.apache.hadoop.hive.ql.io.CombineHiveInputFormat hive.optimize.bucketmapjoin = true; //默认值为false hive.optimize.bucketmapjoin.sortedmerge = true; //默认值为false