Hive 连接(Joins)操作全面解析
在 Hive 大数据处理中,连接(Joins)操作是非常重要且常用的一部分。本文将对 Hive 中连接操作涉及的语法、示例、限制以及优化等多个方面进行详细总结,帮助大家更好地理解和运用 Hive 的连接功能。
一、连接语法
Hive 支持多种连接语法形式,具体如下:
(一)基础语法
连接表:表引用 [内] 连接 表因子 [连接条件]表引用 {左|右|全} [外] 连接 表引用 连接条件表引用 左半连接 表引用 连接条件表引用 交叉连接 表引用 [连接条件](自 Hive 0.10 起)表引用:表因子连接表表因子:表名 [别名]表子查询 别名(表引用)连接条件:使用“ON”关键字加表达式
(二)版本相关语法扩展
- 0.13.0 及以上版本:引入了隐式连接表示法(参考 HIVE - 5558),此时在“FROM”子句中可以用逗号分隔多个表来进行连接,无需写“JOIN”关键字,例如:
SELECT *
FROM table1 t1, table2 t2, table3 t3
WHERE t1.id = t2.id AND t2.id = t3.id AND t1.zipcode = '02535';
同时,该版本开始支持在连接条件中使用非限定列引用(参考 HIVE - 6393),不过若一个非限定列引用能对应到多个表时,Hive 会将其标记为有歧义的引用。
- 2.2.0 及以上版本:支持“ON”子句中的复杂表达式(参考 HIVE - 15211、HIVE - 15251),而在此之前,连接条件只支持等式条件,语法限制如下:
连接条件:ON 等式表达式(AND 等式表达式)*
等式表达式:表达式 = 表达式
二、连接示例及要点
(一)复杂连接表达式
以下都是合法的连接示例,说明了 Hive 允许复杂的连接表达式写法:
SELECT a.* FROM a JOIN b ON (a.id = b.id)
SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department = b.department)
SELECT a.* FROM a LEFT OUTER 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)
(三)Map/Reduce 任务转换
- 若每个表在连接子句中使用相同的列,Hive 会把多表连接转换为单个 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 任务:
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 阶段,序列中的最后一个表会通过 Reduce 阶段流式处理,其他表则缓冲。合理安排表顺序(如将大表放最后)有助于减少 Reduce 阶段缓冲所需内存,例如:
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
可以通过 STREAMTABLE
提示指定要流式处理的表,若省略该提示,默认流式处理最右边的表。
(四)外连接特点及注意事项
左、右和全外连接可对外连接中无匹配项的情况进行控制。例如左外连接:
SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key = b.key)
会为 a
表每行返回结果,有匹配键时返回对应值,无匹配时 b
的值为 NULL
。
需注意连接操作在 WHERE
子句之前执行,所以限制输出结果的条件放置位置很关键,尤其在外连接时。错误放置条件可能导致不符合预期的筛选结果,正确语法示例如下:
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
连接,顺序改变可能导致结果与预期不符,需根据实际需求合理安排连接顺序。
(六)左半连接
左半连接(LEFT SEMI JOIN)可高效实现不相关的 IN/EXISTS
子查询语义,不过其限制是右表只能在连接条件(ON
- 子句)中被引用,不能出现在 WHERE
或 SELECT
等子句中。例如:
SELECT a.key, a.value
FROM a
WHERE a.key in(SELECT b.keyFROM B);
可重写为:
SELECT a.key, a.val
FROM a LEFT SEMI JOIN b ON (a.key = b.key)
三、MapJoin 相关限制
如果除一个表之外的其他连接表都较小,连接可以作为仅 Map 任务执行(无需 Reducer),例如:
SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a JOIN b ON a.key = b.key
但存在诸多不支持的情况,像“Union Followed by a MapJoin”“Lateral View Followed by a MapJoin”等多种组合都是不支持的。另外,配置变量 hive.auto.convert.join
(若设置为 true
)可在运行时自动将符合条件的连接转换为 MapJoin,通常应优先使用该配置变量,而 MAPJOIN
提示建议仅在特定情况(如输入已分区、排序且要转换为对应特殊 Map 侧连接时)下使用。
同时,还有一些可配置参数用于控制 MapJoin 的转换,比如 hive.auto.convert.join.noconditionaltask
决定是否基于输入文件大小将普通连接转换为 MapJoin,hive.auto.convert.join.noconditionaltask.size
则规定了具体的文件大小阈值(默认 10MB),满足条件时直接转换。
四、连接优化
Hive 中涉及连接的优化包括外连接中的谓词下推等内容,可参考 Hive Outer Join Behavior
获取外连接谓词下推相关信息。另外,Hive 0.11 版本在连接优化方面也有增强功能,在增强优化中(参考 HIVE - 3784 及相关 JIRAs),对提示(hints)的使用有所弱化。