Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Excluindo registros de uma tabela unida a outra tabela SQL


Você não precisa usar OUTER JOIN exceto para verificar quantas linhas serão resp. não ser excluído.

Um exemplo de tal consulta veja abaixo (eu uso dados de teste gerados fornecidos no final da resposta)
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   

Com o tamanho dos seus dados, você deve usar um HASH JOIN com full table scan em ambas as tabelas para obter um desempenho aceitável.

Existem basicamente duas opções de como fazer o DELETE

Visualização de associação atualizável

Observe que, neste caso, sua pequena tabela deve ter um índice exclusivo em ID, VERSION (ou uma chave primária)
create unique index delta_idx on delta(id,version);

Ao contrário, a tabela BIG não deve ter essa restrição . Isso é importante porque indica claramente que sua tabela BIG é a única tabela preservadora de chaves na visualização de junção.

Simples, coloque uma junção na pequena tabela não pode duplicar linhas da mesa grande devido à restrição única

Consulte aqui mais informações sobre Atualização de visualizações de junção
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
)

O delete acima remove linhas do BIG table porque esta é a única tabela preservadora de chaves (veja a discussão acima)

Este DML leva a um HASH JOIN

Excluir com EXISTS

Se sua pequena tabela não tiver chave primária (ou seja, pode conter linhas duplicadas com o mesmo ID and VERSION ) você deve substituir para a solução proposta em outra resposta .
DELETE FROM big 
    WHERE EXISTS (SELECT null
                  FROM delta
                  WHERE delta.id = big.id and delta.version = big.version
                 ) 

Nenhum índice é necessário e você deve esperar um plano de execução com HASH JOIN RIGHT SEMI , o que significa que ambas as abordagens não são realmente diferentes.

Dados de amostra para teste
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);