Hive 低效的嵌套连接

Hive inefficient nested joins

我有两个大的 Hive tables(十亿条记录),它们可以通过一个公共键(即事务 ID)连接起来。 table_a 包含所有交易 ID,table_b 有一些时间的交易。

理论上,table 中不应有重复的交易 ID。实际上,有一些重复项,虽然它们的数量相对较少,但 many:many 连接有可能导致问题。我正在基于此数据构建模型,作为第一步,忽略所有具有重复交易 ID 的记录可能更容易。

我写了一个丑陋的 Hive 查询,虽然它在逻辑上做了它需要做的事情,但效率低得可怕:

SELECT
   table_a.someCol,
   table_b.anotherCol,
   [etc...]
FROM
    (SELECT
       table_a.*
     FROM table_a
     INNER JOIN
       (SELECT
          transaction_id
        FROM table_a
        GROUP BY transaction_id
        HAVING COUNT(*) = 1) unique_transaction_ids
    ON table_a.transaction_id = unique_transaction_ids.transaction_id) table_a_unique_transaction_ids_only
LEFT OUTER JOIN
    (SELECT
       table_b.*
     FROM table_b
     INNER JOIN
      (SELECT
         transaction_id
       FROM table_b
       GROUP BY transaction_id
       HAVING COUNT(*) = 1) unique_transaction_ids
    ON table_b.transaction_id = unique_transaction_ids.transaction_id) table_b_unique_transaction_ids_only
ON table_a_unique_transaction_ids_only.transaction_id = table_b_unique_transaction_ids_only.transaction_id;

工作原理:

首先,为两个 table 创建一个仅出现一次的交易 ID 列表:

SELECT
    transaction_id
FROM table_?
GROUP BY transaction_id
HAVING COUNT(*) = 1

然后通过将唯一事务子查询内部连接到原始 tables 来过滤 tables。

最后,对过滤后的子查询进行左外连接。

有没有更有效的写法(例如使用ROW_NUMBER() OVER ...等分析函数)?

如果你想 table_atable_b 在一起,LEFT OUTER JOIN 似乎是不可避免的。可以避免这两个自连接。由于您希望 transaction_id 只出现一次,因此您可以在其余列上使用 MAX()MIN() 而不会丢失信息(即使它们不是数字列)。像

select transaction_id
  , max(col1) col1
  , max(col2) col2
        .
        .
        .
  , max(coln) coln
from table_a
group by transaction_id
having count(transaction_id) = 1

这是一种 "pull columns through" 到下一个 "level" 而不必 group by 他们的方法。如果你有很多列,写起来可能会很乏味,但通常值得避免两次自连接。