Před zodpovězením mých otázek bych to řešil takto:
Minimalizujte počet prohlášení a práce, kterou vydávají v relativním vyjádření.
Všechny scénáře předpokládají, že máte tabulku ID (PURGE_IDS
) odstranit z TABLE_1
, TABLE_2
, atd.
Zvažte použití CREATE TABLE AS SELECT pro skutečně velká smazání
Pokud nedochází k žádné souběžné aktivitě a odstraňujete 30+ % řádků v jedné nebo více tabulkách, nemažte; provést create table as select
s řádky, které si chcete ponechat, a vyměňte novou tabulku za starou. INSERT /*+ APPEND */ ... NOLOGGING
je překvapivě levné, pokud si to můžete dovolit. I když máte nějakou souběžnou aktivitu, možná budete moci použít předefinování tabulky online k přestavbě tabulky na místě.
Nespouštějte příkazy DELETE, o kterých víte, že nesmažou žádné řádky
Pokud hodnota ID existuje maximálně v jedné ze šesti tabulek, sledujte, která ID jste odstranili – a nepokoušejte se tato ID odstranit z žádné z ostatních tabulek.
CREATE TABLE TABLE1_PURGE NOLOGGING
AS
SELECT ID FROM PURGE_IDS INNER JOIN TABLE_1 ON PURGE_IDS.ID = TABLE_1.ID;
DELETE FROM TABLE1 WHERE ID IN (SELECT ID FROM TABLE1_PURGE);
DELETE FROM PURGE_IDS WHERE ID IN (SELECT ID FROM TABLE1_PURGE);
DROP TABLE TABLE1_PURGE;
a opakujte.
Pokud musíte, spravujte souběžnost
Dalším způsobem je použití smyčky PL/SQL nad tabulkami a vydání příkazu delete s omezením počtu řádků. To je s největší pravděpodobností vhodné, pokud dochází k významnému souběžnému zatížení vkládání/aktualizace/mazání u tabulek, u kterých spouštíte odstraňování.
declare
l_sql varchar2(4000);
begin
for i in (select table_name from all_tables
where table_name in ('TABLE_1', 'TABLE_2', ...)
order by table_name);
loop
l_sql := 'delete from ' || i.table_name ||
' where id in (select id from purge_ids) ' ||
' and rownum <= 1000000';
loop
commit;
execute immediate l_sql;
exit when sql%rowcount <> 1000000; -- if we delete less than 1,000,000
end loop; -- no more rows need to be deleted!
end loop;
commit;
end;