hive join的替代方案

时间:2017-02-20 13:19:49

标签: sql hadoop hive query-optimization hiveql

我的hive中有两个观点

+------------+
| Table_1    |
+------------+
| hash       |
| campaignId |
+------------+

+-----------------+
| Table_2         |
+-----------------+
| campaignId      |
| accountId       |
| parentAccountID |
+-----------------+

现在我必须抓取' Table_1'通过accountId&过滤的数据parentAccountID,我为此编写了以下查询:

SELECT /*+ MAPJOIN(T2) */ T1.hash, COUNT(T1.campaignId) num_campaigns
FROM Table_1 T1
JOIN Table_2 T2 ON T1.campaignId = T2.campaignId
WHERE (T2.accountId IN ('aid1', 'aid2') OR T2.parentAccountID IN ('aid1', 'aid2')
GROUP BY T1.hash

此查询正在运行但速度很慢。有没有更好的替代方案(JOIN)?

我正在通过spark从卡夫卡读到Table_1 幻灯片持续时间为5秒
窗口持续时间为2分钟

虽然Table_2在RDBMS中,但是火花正在通过jdbc读取,而且它有4500条记录。

每隔5秒,kafka以CSV格式记录大约2K记录 我需要在5秒内处理数据,但目前需要8到16秒。

根据建议:

  1. 我已按行campaignId&列重新分区Table_1哈希分别。
  2. 我已按照accountId&列重新分区Table_2 parentAccountID分别。
  3. 我已经实施了MAPJOIN。
  4. 但仍然没有改善。

    注意: 如果我删除了窗口持续时间,那么该过程会在一段时间内执行。可能是因为要处理的数据较少。但这不是要求。

5 个答案:

答案 0 :(得分:0)

使用正确的索引,以下内容可以更快:

iframe

第一个可以考虑SELECT T1.* FROM Table_1 T1 JOIN Table_2 T2 ON T1.campaignId = T2.campaignId WHERE T2.accountId IN ('aid1', 'aid2') UNION ALL SELECT T1.* FROM Table_1 T1 JOIN Table_2 T2 ON T1.campaignId = T2.campaignId WHERE T2.parentAccountID IN ('aid1', 'aid2') AND T2.accountId NOT IN ('aid1', 'aid2') ; 上的索引和Table_2(accountId, campaignId)上的第二个索引。

答案 1 :(得分:0)

由于这是我们所讨论的Hive,您需要关注的不仅仅是传统的DBMS。

  • 减少IO。使用压缩的列式格式表示数据。 ORC或Parquet。 RC。首先执行此操作,将表转换为ORC。除非数据是压缩的和柱状的,否则没有其他任何东西会产生很大影响。
  • 为Hive选择正确的JOIN策略。此old 2011 paper仍然相关。
  • Bucketize你的桌子
  • 使用现代执行引擎:TezSpark

答案 2 :(得分:0)

如果T2过滤小到足以适合内存,请尝试重写查询并将过滤器移动到子查询中,并查看是否将在mapper上执行连接。此外,您不需要T2中的列,可以使用左半连接而不是内连接:

set hive.cbo.enable=true; 
set hive.auto.convert.join=true;

SELECT T1.* 
FROM Table_1 T1 
LEFT SEMI JOIN 
     (select campaignId  from Table_2 T2 
        where T2.accountId IN ('aid1', 'aid2') 
           OR T2.parentAccountID IN ('aid1', 'aid2')
     ) T2 ON T1.campaignId = T2.campaignId 
;

答案 3 :(得分:0)

我建议您使用本机Spark转换而不是HiveSQL:

1.将表2中的数据(RDBMS)读入RDD&把它放在缓存中 例如:

rddTbl1.map(campaignIdKey, (accountId, parentAccountId)) //filter out before getting into RDD if needed
rddTbl2.cache()

2.现在读取Table_1流(Kafka)

//get campaigns of relevant account & parentaccountid
val rddTbl2_1 = rddTbl2.filter(x => x._2._1.equals("aid1") || x._2._1.equals("aid2") || x._2._2.equals("aid1") || x._2._2.equals("aid2"))

dstream.foreachRDD{ rddTbl1 =>
  rddTbl1.map(x => x._2.split(",")).
          map(x => (x(1), x(2)). //campaignId, hash
          join(rddTbl2_1).
          map(x => (x._2._1, 1)). //get (hash,1)
          reduceByKey(_+_).
          foreach(println) //save it if needed
}

答案 4 :(得分:0)

确定..

这是我最终做的。

我创建了表2的哈希 然后通过使用广播变量,我将该数据传递给每个节点。

这让我省去了加入的麻烦。

谢谢大家的时间和帮助。 快乐的编码:)