Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Löschen von Datensätzen aus einer Tabelle, die mit einer anderen Tabelle verknüpft ist SQL

Sie müssen OUTER JOIN nicht verwenden bis auf die Prüfung, wie viele Zeilen bzw. wird nicht gelöscht werden.

Ein Beispiel für eine solche Abfrage finden Sie unten (ich verwende generierte Testdaten, die am Ende der Antwort bereitgestellt werden)

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   

Bei Ihrer Datengröße sollten Sie einen HASH JOIN verwenden mit full table scan auf beiden Tischen, um eine akzeptable Leistung zu erzielen.

Es gibt grundsätzlich zwei Möglichkeiten, wie man DELETE durchführt

Aktualisierbare Beitrittsansicht

Beachten Sie, dass Ihre kleine Tabelle in diesem Fall einen eindeutigen Index haben muss ID, VERSION (oder ein Primärschlüssel)

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

Im Gegensatz dazu sollte die BIG-Tabelle keine solche Einschränkung haben . Dies ist wichtig, da es deutlich anzeigt, dass Ihre BIG-Tabelle die einzige schlüsselerhaltende Tabelle ist in der Join-Ansicht.

Fügen Sie der kleinen Tabelle einfach einen Join hinzu Kann Zeilen nicht duplizieren vom großen Tisch aufgrund der einzigartigen Beschränkung

Siehe hier Weitere Informationen zum Aktualisieren von Beitrittsansichten

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
)

Das delete oben entfernt Zeilen aus BIG Tabelle, da dies die einzige schlüsselerhaltende Tabelle ist (siehe die Diskussion oben)

Diese DML führt zu einem HASH JOIN

Löschen mit EXISTS

Wenn Ihre kleine Tabelle keinen Primärschlüssel hat (d. h. sie kann doppelte Zeilen mit derselben ID and VERSION enthalten ) müssen Sie zurückgreifen zu der in andere Antwort vorgeschlagenen Lösung .

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

Es sind keine Indizes erforderlich und Sie sollten einen Ausführungsplan mit HASH JOIN RIGHT SEMI erwarten , was bedeutet, dass sich beide Ansätze nicht wirklich unterscheiden.

Beispieldaten für 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);