我的SQL MERGE语句运行时间过长

时间:2017-10-05 14:01:55

标签: hive sql-merge

我有这个Hive MERGE声明:

MERGE INTO destination dst
USING (
  SELECT

   -- DISTINCT fields
      company
    , contact_id as id
    , ct.cid as cid

     -- other fields
    , email
    , timestamp_utc
    -- there are actually about 6 more 

    -- deduplication
    , ROW_NUMBER() OVER (
         PARTITION BY company
       , ct.id
       , contact_id
         ORDER BY timestamp_utc DESC
    ) as r

  FROM
    source
  LATERAL VIEW explode(campaign_id) ct AS cid
) src
ON
        dst.company = src.company
    AND dst.campaign_id = src.cid
    AND dst.id = src.id

-- On match: keep latest loaded
WHEN MATCHED
    AND dst.updated_on_utc < src.timestamp_utc
    AND src.r = 1
THEN UPDATE SET
    email =  src.email
  , updated_on_utc = src.timestamp_utc

WHEN NOT MATCHED AND src.r = 1 THEN INSERT VALUES (
    src.id

  , src.email

  , src.timestamp_utc

  , src.license_name
  , src.cid
)
;

哪个运行很长时间(磁盘上7GB的avro压缩数据为30分钟)。 我想知道是否有任何SQL方法可以改进它。

ROW_NUMBER()用于对源表进行重复数据删除,因此在MATCH子句中我们只选择最早的行。

我不确定的一件事是hive says

  

如果ON子句是这样的话,SQL标准要求引发错误   源中超过1行与目标中的行匹配。这个检查是   计算成本高,可能影响a的整体运行时间   MERGE声明显着。 hive.merge.cardinality.check = false可能   用于禁用检查的风险由您自行承担。如果检查是   禁用,但声明有这样的交叉连接效果,它可能会导致   数据损坏。

我确实禁用了基数检查,因为虽然ON语句可能在源代码中提供2行,但由于MATCH子句中的r = 1,这些行仅限于1。

总的来说,我喜欢这个MERGE声明,但它太慢了,任何帮助都会受到赞赏。

请注意,目标表已分区。源表不是因为它是一个外部表,每次运行必须完全合并,所以完全扫描(在后台已经合并的数据文件被删除,新文件在下次运行之前添加)。在这种情况下,不确定分区是否有用

我做了什么:

  • 使用hdfs / hive / yarn配置
  • 尝试使用临时表(2个步骤)而不是单个MERGE,运行时间跳跃超过2个小时。

1 个答案:

答案 0 :(得分:1)

选项1:移动where src.r = 1子查询中的过滤器src,并检查合并性能。这将减少合并前的源行数。

其他两个选项不需要ACID模式。完全目标重写。

选项2:使用UNION ALL + row_number重写(这应该是最快的):

insert overwrite table destination 
select 
company
, contact_id as id
, ct.cid as cid
, email
, timestamp_utc
, -- add more fields 
from
(
select --dedupe, select last updated rows using row_number
s.*
, ROW_NUMBER() OVER (PARTITION BY company, ct.id , contact_id ORDER BY timestamp_utc DESC) as rn
from
(
select --union all source and target
company
, contact_id as id
, ct.cid as cid
, email
, timestamp_utc
, -- add more fields 
from source LATERAL VIEW explode(campaign_id) ct AS cid
UNION ALL
select 
company
, contact_id as id
, ct.cid as cid
, email
, timestamp_utc
,-- add more fields 
from destination
)s --union all
where rn=1 --filter duplicates
)s-- filtered dups

如果source包含大量重复项,则可以在union之前对src子查询应用其他row_number过滤。

使用完全加入的另一种方法: https://stackoverflow.com/a/37744071/2700344