我有一张桌子,上面有3000万条记录。在执行插入操作时,我需要避免违反Unique约束。
当我使用这种NOT EXIST方法时,插入将永远花费。实际上,它在运行24小时后无法完成。而且我不能使用ignore_row_on_dupkey_index
提示,因为此表具有1个以上的PK列。
另一个选择是插入子集。但是我想知道在进行子设置之前是否还有其他方法。
insert into tlb1 a
select * from tlb2 b
where not exists (select 'x' from tlb1 c
where b.pk = c.pk)
答案 0 :(得分:1)
重要的决定取决于插入的numbe rof行,即表TBL2
中的行数
如果此数字相当低(例如成百上千),则可以安全地使用您的方法,前提是PK
列上有一个索引-斜线应强制执行唯一约束。 / p>
请检查所使用的执行计划是否类似于以下内容
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 110 | 2860 | 113 (0)| 00:00:02 |
| 1 | LOAD TABLE CONVENTIONAL | TBL1 | | | | |
| 2 | NESTED LOOPS ANTI | | 110 | 2860 | 113 (0)| 00:00:02 |
| 3 | TABLE ACCESS FULL | TBL2 | 110 | 1430 | 3 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | TBL1_IXD | 1 | 13 | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("B"."PK"="C"."PK")
NESTED LOOPS ANTI
意味着对于每个插入的行,将进行一次索引查找,以检查目标表中是否已存在键。
这对于插入的行数较少会很好。对于较大的插入(数百万行),优化器将切换到HASH JOIN RIGHT ANTI
,即,两个表中的所有行都将合并以得到可能的重复项。
这可能会花费一些时间(但通常不会是24小时),并且使用DML Error Logging的方法可以消除联接的需要。
INSERT INTO tbl1 (pk)
SELECT pk
FROM tbl3
LOG ERRORS INTO err$_tbl1 ('dedup tbl3') REJECT LIMIT UNLIMITED;
这种方法将很好地扩展,特别是当重复项的数量比插入的行数少时。它可与普通插入物媲美:
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 876K| 10M| 427 (1)| 00:00:06 |
| 1 | LOAD TABLE CONVENTIONAL | TBL1 | | | | |
| 2 | TABLE ACCESS FULL | TBL3 | 876K| 10M| 427 (1)| 00:00:06 |
---------------------------------------------------------------------------------