Oracle
 sql >> база данни >  >> RDS >> Oracle

Изтриване на записи от една таблица, свързани към друга таблица SQL

Не е необходимо да използвате 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 не трябва да няма такова ограничение . Това е важно, защото ясно показва, че вашата ГОЛЯМА таблица е единствената таблица със запазване на ключ в изгледа за присъединяване.

Просто поставете съединение към малката таблица не може да дублира редове от голямата маса поради уникалното ограничение

Вижте тук повече информация относно Актуализиране на изгледи за присъединяване

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 ) трябва да резервно към решението, предложено в друг отговор .

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Смесване на DDL и DML изрази в един скрипт

  2. Java - Пребройте точно 60 знака от низ със смес от UTF-8 и различни от UTF-8 знаци

  3. Получаване на времевия печат на файл с помощта на PL/SQL

  4. Използвайте като „%“ и съпоставете NULL стойности с NUMBER колони

  5. Как да получите информация за тип, дефиниран от потребителя?