您不需要使用OUTER JOIN,除了检查将相应的行数。 不会被删除。
此类查询的示例见下文(我使用答案末尾提供的生成的测试数据)
with del as (
select delta.id, delta.version,
decode(big.id,null,0,1) is_deleted
from delta
left outer join big
on delta.id = big.id and delta.version = big.version
)
select is_deleted, count(*) cnt, max(id||'.'||version) eg_id_vers
from del
group by is_deleted;
IS_DELETED CNT EG_ID_VERS
---------- ---------- ----------
1 20000 99995.0
0 20 100100.0
根据您的数据大小,您应该在两个表上使用HASH JOIN 和full table scan 以获得可接受的性能。
DELETE基本上有两种选择
可更新的加入视图
请注意,在这种情况下,您的小表必须具有唯一索引 ID, VERSION(或主键)
create unique index delta_idx on delta(id,version);
相反,BIG 表应该没有这样的约束。这很重要,因为它清楚地表明您的 BIG 表是连接视图中唯一的一个键保留表。
简单地加入小表由于唯一约束
,不能从大表复制行
有关更新加入视图
的更多信息,请参阅
here
delete from
(
select delta.id, delta.version, big.id big_id, big.version
from big
join delta
on delta.id = big.id and delta.version = big.version
)
上面的delete 会从BIG 表中删除行,因为这是唯一的键保留表(参见上面的讨论)
此 DML 导致 HASH JOIN
使用 EXISTS 删除
如果您的小表没有主键(即它可以包含具有相同ID and VERSION 的重复行),您必须回退到other answer 中提出的解决方案。
DELETE FROM big
WHERE EXISTS (SELECT null
FROM delta
WHERE delta.id = big.id and delta.version = big.version
)
不需要索引,您应该期待一个带有HASH JOIN RIGHT SEMI 的执行计划,这意味着这两种方法并没有真正的不同。
测试样本数据
create table big as
select
trunc(rownum/10) id, mod(rownum,10) version,
lpad('x',10,'Y') pad
from dual connect by level <= 1000000;
/* the DELTA table has 50 times less rows,
allow some rows out of range of the BIG table - those rows will not be deleted **/
drop table delta;
create table delta as
select
trunc(rownum*50/10) id, mod(rownum*50,10) version
from dual connect by level <= 1001000/50;
create unique index delta_idx on delta(id,version);