Oracle
 sql >> Database >  >> RDS >> Oracle

Eliminazione di record da una tabella unita a un'altra tabella SQL

Non è necessario utilizzare OUTER JOIN fatta eccezione per il controllo di quante righe risp. non essere cancellato.

Un esempio di tale query vedi sotto (uso i dati di test generati forniti alla fine della risposta)

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   

Con la dimensione dei tuoi dati dovresti usare un HASH JOIN con full table scan su entrambi i tavoli per ottenere prestazioni accettabili.

Ci sono fondamentalmente due opzioni su come eseguire DELETE

Vista di partecipazione aggiornabile

Nota che in questo caso la tua piccola tabella deve avere un indice univoco su ID, VERSION (o una chiave primaria)

create unique index delta_idx on delta(id,version);

Al contrario, la tabella BIG non dovrebbe avere tale vincolo . Questo è importante, perché indica chiaramente che la tua tabella BIG è l'unica tabella di conservazione delle chiavi nella vista di unione.

Metti semplicemente un join nella piccola tabella impossibile duplicare le righe dal grande tavolo per il vincolo unico

Vedi qui ulteriori informazioni sull'aggiornamento di un join Views

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
)

Il delete sopra rimuove le righe da BIG tabella perché questa è l'unica tabella di conservazione delle chiavi (vedi la discussione sopra)

Questo DML porta a un HASH JOIN

Elimina con EXISTS

Se la tua piccola tabella non ha una chiave primaria (cioè può contenere righe duplicate con lo stesso ID and VERSION ) devi fallback alla soluzione proposta in altra risposta .

DELETE FROM big 
    WHERE EXISTS (SELECT null
                  FROM delta
                  WHERE delta.id = big.id and delta.version = big.version
                 ) 

Non sono richiesti indici e dovresti aspettarti un piano di esecuzione con HASH JOIN RIGHT SEMI , il che significa che entrambi gli approcci non sono molto diversi.

Dati di esempio per il test

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);