Hive Joins

Join Syntax

Hive 支持以下用于联接表的语法:

join_table:
    table_reference [INNER] 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 expression

有关此连接语法的上下文,请参见Select Syntax

Version 0.13.0+: Implicit join notation

从 Hive 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';

Version 0.13.0+: Unqualified column references

从 Hive 0.13.0(请参阅HIVE-6393)开始的联接条件中支持不合格的列引用。 Hive 尝试根据 Join 的 Importing 来解决这些问题。如果不合格的列引用解析为多个表,则 Hive 会将其标记为歧义引用。

For example:

CREATE TABLE a (k1 string, v1 string);
CREATE TABLE b (k2 string, v2 string);

SELECT k1, v1, k2, v2
FROM a JOIN b ON k1 = k2;

Version 2.2.0+: Complex expressions in ON clause

从 Hive 2.2.0 开始,支持 ON 子句中的复杂表达式(请参见HIVE-15211HIVE-15251)。在此之前,Hive 不支持不是相等条件的联接条件。

特别是,连接条件的语法受到如下限制:

join_condition:     ON equality_expression ( AND equality_expression )*
equality_expression:     expression = expression

Examples

编写联接查询时要考虑的一些要点如下:

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)

是有效的联接。

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 列,因此被转换为单个 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 作业,因为在第一个联接条件中使用了 b 中的 key1 列,而在第二个连接条件中使用了 b 中的 key2 列。第一个 map/reduce 作业将 a 与 b 联接,然后将结果与 c 联接到第二个 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/归约作业中联接,并且表 a 和 b 的键的特定值的值被缓存在化简器的内存中。然后,对于从 c 中检索的每一行,将使用缓冲的行来计算联接。同样的

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

计算联接涉及两个 Map/归约作业。其中的第一个将 a 与 b 连接起来,并缓冲 a 的值,同时在减速器中流式传输 b 的值。这些作业中的第二个将缓冲第一个连接的结果,同时将 c 的值通过简化器流式传输。

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/归约作业中联接,并且表 b 和 c 的键的特定值的值被缓冲在化简器的内存中。然后,对于从 a 检索的每一行,将使用缓冲的行来计算联接。如果省略 STREAMTABLE 提示,则 Hive 将流化 Connecting 最右边的表。

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 的 LEFT,因此保留了 a 中的所有行;右外连接将保留 b 中的所有行,而全外连接将保留 a 中的所有行和 b 中的所有行。 OUTER JOIN 语义应符合标准 SQL 规范。

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'

将在 b 上加入 a,生成 a.val 和 b.val 的列表。但是,WHERE 子句也可以引用联接输出中的 a 和 b 的其他列,然后将其过滤掉。但是,只要 JOIN 中的一行找到 a 的键而 b 的键都没有,则 b 的所有列都将为 NULL, 包括 ds 列 。这就是说,您将过滤掉没有有效 b.key 的所有联接输出行,因此,您超出了 LEFT OUTER 的要求。换句话说,如果您在 WHERE 子句中引用 b 的任何列,则联接的 LEFT OUTER 部分无关紧要。相反,在进行外部联接时,请使用以下语法:

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')

..结果是对联接的输出进行了预过滤,对于具有有效 a.key 但不匹配 b.key 的行,您将不会遇到后过滤麻烦。相同的逻辑适用于 RIGHT 和 FULL 连接。

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)

...首先在 b 上加入 a,将 a 或 b 中所有没有其他键的东西都扔掉。然后将精简表连接到 c。如果 a 和 c 中都存在一个键但 b 中不存在键,这将提供不直观的结果:整个行(包括 a.val1,a.val2 和 a.key)都被删除在“ a JOIN b”步骤中,因为不在 b。结果中没有 a.key,因此当它与 c 一起左移时,由于没有 c.key 与 a.key 匹配,因此 c.val 不会加入(因为 a 中的行已删除) )。同样,如果这是一个 RIGHT OUTER JOIN(而不是 LEFT),我们最终会得到一个更奇怪的效果:NULL,NULL,NULL,c.val,因为即使我们将 a.key = c.key 指定为联接键,我们删除了所有与第一个 JOIN 不匹配的行。
为了获得更直观的效果,我们应该改为 FROM FROM c 左外连接 a ON(c.key = a.key)左外连接 b ON(c.key = b.key)。

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

不需要减速器。对于 A 的每个 Map 器,B 都会被完全读取。限制是不能执行 a FULL/RIGHT OUTER JOIN b

SELECT /*+ MAPJOIN(b) */ a.key, a.value
  FROM a JOIN b ON a.key = b.key

只能在 Map 器上完成。并非完全为 A 的每个 Map 器获取 B,而是仅获取所需的存储桶。对于上面的查询,A 的 Map 器处理存储桶 1 将仅获取 B 的存储桶 1.这不是默认行为,由以下参数控制

set hive.optimize.bucketmapjoin = true
SELECT /*+ MAPJOIN(b) */ a.key, a.value
  FROM A a JOIN B b ON a.key = b.key

只能在 Map 器上完成。 A 的存储桶的 Map 器将遍历 B 的对应存储桶。这不是默认行为,需要设置以下参数:

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

MapJoin Restrictions

SELECT /*+ MAPJOIN(b) */ a.key, a.value
  FROM a JOIN b ON a.key = b.key

不需要减速器。对于 A 的每个 Map 器,B 都会被完全读取。

select /*+MAPJOIN(smallTableTwo)*/ idOne, idTwo, value FROM
  ( select /*+MAPJOIN(smallTableOne)*/ idOne, idTwo, value FROM
    bigTable JOIN smallTableOne on (bigTable.idOne = smallTableOne.idOne)                                                   
  ) firstjoin                                                             
  JOIN                                                                  
  smallTableTwo ON (firstjoin.idTwo = smallTableTwo.idTwo)

不支持上述查询。如果没有 mapjoin 提示,则以上查询将作为 2 个仅 map 作业执行。如果用户事先知道 Importing 足够小以适合内存,则可以使用以下可配置参数来确保查询在单个 map-reduce 作业中执行。

Join Optimization

外部联接中的谓词下推

有关外部联接中的谓词下推的信息,请参见Hive 外部联接行为

Hive 版本 0.11 中的增强功能

请参阅Join Optimization,以获取有关 Hive 版本 0.11.0 中引入的加入优化的增强功能的信息。在增强的优化(HIVE-3784和相关的 JIRA)中不再强调使用提示。

首页