我有一个配置单元合并语句:
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说:
sql标准要求,如果on子句使源中的多行与目标中的行匹配,则会引发错误。此检查的计算开销很大,可能会显著影响merge语句的整体运行时。hive.merge.cardinality.check=false可用于禁用检查,风险自负。如果检查被禁用,但语句具有这种交叉连接效应,则可能导致数据损坏。
我确实禁用了基数检查,因为虽然on语句在source中可能会给出2行,但是由于match子句后面的r=1,这些行被限制为1。
总的来说,我喜欢这个合并声明,但它只是太慢,任何帮助将不胜感激。
注意,目标表是分区的。源表不是,因为它是一个外部表,每次运行都必须完全合并,因此完全扫描(在后台,已合并的数据文件将被删除,新文件将在下次运行之前添加)。不确定分区在这种情况下是否有用
我所做的:
播放hdfs/Hive/Yarn配置
尝试使用临时表(2个步骤)而不是单个合并,运行时间跳到2小时以上。
1条答案
按热度按时间4jb9z9bj1#
选项1:移动过滤器
where src.r = 1
内部src
子查询并检查合并性能。这将减少合并前的源行数。其他两个选项不需要acid模式。执行完全目标重写。
选项2:使用union all+行号重写(这应该是最快的一个):
如果源中包含大量重复项,则可以在联合之前对src子查询应用额外的行号筛选。
还有一种方法是使用fulljoin:https网址:stackoverflow.com/a/37744071/2700344