首页 > 解决方案 > vertica中的“在连接中检测到重复的合并键”

问题描述

我正在尝试使用 MERGE 将聚合数据插入到表集合中。对于每个表,有些字段可以为空,有些则不能。在 fieldA 和 FieldB 上声明了两个主键。当我运行 MERGE 语句时,我收到“在连接中检测到重复的 MERGE 键”错误。谁能帮我解决这个问题。

注意:当我截断目标表时,如果对临时表中的 fieldC 或 FieldD 进行任何更新操作,然后运行合并查询,它工作正常。但是下次当临时表中的 fieldC 或 fieldD 发生任何更新操作然后运行合并查询时,它会给出此错误。

示例伪语法:

CREATE TABLE target (
fieldA varchar,
fieldB varchar,
fieldC varchar null,
fieldD int not null,
FieldE int,
Constraint target_pk primary key(fieldA, fieldB));

CREATE TABLE temp (
fieldA varchar,
fieldB varchar,
fieldC varchar null,
fieldD int not null,
fieldE int,
Constraint temp_pk primary key(fieldA, fieldB));

MERGE INTO target trg
USING temp tmp ON (
    trg.FieldA = tmp.FieldA
    AND trg.FieldB = tmp.FieldB)
   
WHEN MATCHED THEN UPDATE
    SET fieldC = tmp.fieldC ,
    fieldD= tmp.fieldD,
    fieldE=temp.fieldE

WHEN NOT MATCHED THEN INSERT (
    FieldA ,
    FieldB ,
    FieldC ,
    fieldD,
    fieldE)
VALUES (
    tmp.FieldA ,
    tmp.FieldB ,
    tmp.FieldC ,
    tmp.fieldD,
    tmp.fieldE);

标签: sqlcommon-table-expressionvertica

解决方案


一开始,目标表是空的,甚至没有包含数据的投影。这样,访问计划就变成了一个简单的插入。事实上,当你用一个空的目标和一个完整的源来解释 MERGE 时,你得到一个空的解释计划。

-- here's a scenario - improved a bit - 
-- never, if you can avoid it, use a VARCHAR with no length info
DROP TABLE IF EXISTS target;
DROP TABLE IF EXISTS temp;
CREATE TABLE target (
fieldA VARCHAR(8) NOT NULL,
fieldB VARCHAR(8) NOT NULL,
fieldC VARCHAR(8) NULL,
fieldD INT        NOT NULL,
FieldE INT,
CONSTRAINT target_pk PRIMARY KEY(fieldA, fieldB)
);

CREATE TABLE temp LIKE target INCLUDING PROJECTIONS;

INSERT INTO temp
          SELECT '1','1','A',1,1
UNION ALL SELECT '1','1','A',1,1 -- note that this is a duplicate of the row above
UNION ALL SELECT '1','2','B',1,2
UNION ALL SELECT '1','3','C',1,3
UNION ALL SELECT '1','4','D',1,4
UNION ALL SELECT '1','5','E',1,5
;
COMMIT;

用空表解释:

EXPLAIN
MERGE INTO target trg
USING temp tmp 
 ON trg.FieldA = tmp.FieldA
AND trg.FieldB = tmp.FieldB
   
WHEN MATCHED THEN UPDATE SET 
    fieldC = tmp.fieldC ,
    fieldD = tmp.fieldD,
    fieldE = tmp.fieldE

WHEN NOT MATCHED THEN INSERT (
    FieldA ,
    FieldB ,
    FieldC ,
    fieldD,
    fieldE
) VALUES (
    tmp.FieldA ,
    tmp.FieldB ,
    tmp.FieldC ,
    tmp.fieldD,
    tmp.fieldE
);
-- out  Access Path:
-- out  
-- out  
-- out  ------------------------------
-- empty.

现在,我执行第一个 MERGE 和 COMMIT:

MERGE INTO target trg
USING temp tmp
 ON trg.FieldA = tmp.FieldA
AND trg.FieldB = tmp.FieldB
WHEN MATCHED THEN UPDATE SET
    fieldC = tmp.fieldC ,
    fieldD = tmp.fieldD,
    fieldE = tmp.fieldE
WHEN NOT MATCHED THEN INSERT (
    FieldA ,
    FieldB ,
    FieldC ,
    fieldD,
    fieldE
) VALUES (
    tmp.FieldA ,
    tmp.FieldB ,
    tmp.FieldC ,
    tmp.fieldD,
    tmp.fieldE
);

COMMIT;
-- out  OUTPUT 
-- out --------
-- out       6                                                              
-- out (1 row)
-- out 
-- out Time: First fetch (1 row): 142.089 ms. All rows formatted: 142.152 ms
-- out Time: First fetch (0 rows): 5.042 ms. All rows formatted: 5.059 ms

我再次解释了 MERGE:

-- out  Access Path:
-- out  +-DML MERGE [Cost: 0, Rows: 0]
-- out  |  Target Projection: dbadmin.target_super
-- out  |  Target Prep:
-- out  | +---> JOIN MERGEJOIN(inputs presorted) [RightOuter] [Cost: 7K, Rows: 10K (NO STATISTICS)] (PATH ID: 1)
-- out  | |      Join Cond: (target.fieldA = VAL(2)) AND (target.fieldB = VAL(2))
-- out  | | +-- Outer -> STORAGE ACCESS for <No Alias> [Cost: 4K, Rows: 10K (NO STATISTICS)] (PATH ID: 2)
-- out  | | |      Projection: dbadmin.target_super
-- out  | | |      Materialize: target.fieldA, target.fieldB, target.fieldC, target.fieldD, target.FieldE, target.epoch
-- out  | | |      Runtime Filters: (SIP1(MergeJoin): target.fieldA), (SIP2(MergeJoin): target.fieldB), (SIP3(MergeJoin): target.fieldA, target.fieldB)
-- out  | | +-- Inner -> SELECT [Cost: 3K, Rows: 10K (NO STATISTICS)] (PATH ID: 3)
-- out  | | | +---> STORAGE ACCESS for tmp [Cost: 3K, Rows: 10K (NO STATISTICS)] (PATH ID: 4)
-- out  | | | |      Projection: dbadmin.temp_super
-- out  | | | |      Materialize: tmp.fieldA, tmp.fieldB, tmp.fieldC, tmp.fieldD, tmp.FieldE

现在您看到有一个DML MERGE操作,它从一个操作中读取JOIN MERGEJOIN

当您 truncatetarget时,投影仍然存在,但为空。事实上,EXPLAIN当目标表被截断时,你也会得到第二个版本,但确实有一个投影。

您遇到了 Vertica 的一个特点,因为它是一个大数据平台,针对性能进行了优化。

  1. 默认情况下,对表的约束是DISABLED,如果您希望启用它,则必须ALTER TABLE ENABLE CONSTRAINT ... - 这样做会大大减慢任何海量数据操作的速度。
  2. 使用禁用的主键约束,您可以插入重复项 - 但随后JOIN使用目标表的主键列 -OUTER解释计划中的表 - 将尝试利用构建计划的唯一性 - 如果遇到则失败重复键。它以一个空的外部目标表成功。

因此,您与包含重复键的完整目标的 MERGE 失败。

您在删除重复项方面需要帮助吗?有一堆带有 [Vertica] 标签的帖子处理这个......


推荐阅读