Probabil ca orice DBA a fost nevoit de-a lungul timpului sa șteargă înregistrări din tabele
cu milioane de înregistrări care au indecși și constrângeri. Atunci ați putut observa ca
operația de ștergere este mare consumatoare de timp iar în plus generează și multe redo loguri și undo data. In funcție de situația cu care va confruntați exista mai multe abordări, voi
încerca sa dau câteva exemple:
1. Presupunem că dorim să ștergem înregistrările din tabela t1 care nu se găsesc în tabela c
Tabela t1 are multe înregistrări iar noi dorim să ștergem 20% din această tabelă. Operația de ștergere se desfășoară într-un interval orar în care baza de date nu este utilizată.
In acesta situație cea mai buna abordare este să creăm o nouă tabelă cu înregistrările
pe care dorim să le păstram, în plus vom efectua această operație fără să generăm redo log. Vă reamintesc că insert-ul este mai rapid decât delete-ul, totodată acesta generează mai puține loguri decât delete-ul.
create table temp nologging as select * from t1 where id in ( select id from c );
--atenție să adaugați constrângerile și indecșii din t1 în temp
drop table t1; --dupa ce verificati cu atentie
ALTER TABLE temp RENAME TO t1;
ALTER TABLE t1 LOGGING;
2. aceeași situație ca în cazul prezentat mai sus cu mențiunea ca operațiunea se desfășoară pe o baza care este în producție 24 din 24.
In acest caz, cea mai buna abordare este sa ștergem puțin cate puțin pentru a nu bloca tabela.
Pentru aceasta situație eu folosesc un loop care executa commit după o mie de înregistrări șterse. Dezavantajul acestei metode este rapiditatea.
DECLARE
coun NUMBER := 0;
total NUMBER := 0;
CURSOR del_record_cur IS
SELECT rowid
FROM t1
WHERE id in ( select id from c ) ;
BEGIN
FOR rec IN del_record_cur LOOP
DELETE FROM t1
WHERE rowid = rec.rowid
and id in ( select id from c ) ;
total := total + 1;
coun := coun + 1;
IF (coun >= 1000) THEN
COMMIT;
coun := 0;
END IF;
END LOOP;
COMMIT;
DBMS_OUTPUT.PUT_LINE('Deleted ' || total || ' records from t1');
END;
3. o alta soluție foarte eficientă este sa partiționați tabela în doua partiții, datele care trebuie șterse mutate într-o partiție iar restul în cealaltă. Aceasta soluție este viabila în cazul în care știți ca în viitor va fi nevoie sa mai efectuați aceeași operațiune. Găsiți detalii despre cum se poate realiza aceasta operațiune în articolul anterior.
4. mai exista situația când nu se pot folosi metodele prezentate mai sus și trebuie folosit delete-ul clasic. In aceast caz va sfătuiesc să colectați statisticile pentru t1 iar pentru un plus de performanta sa dezactivați contragerile din t1 și sa ștergeți indecșii nefolosiți (atenție la coloanele din filtrul query-ului de delete), în cazul de fata dacă exista un index pe coloana id din t1, este de preferat sa nu îl ștergem. Este de preferat varianta clasica atunci cand doriti ca operatiunea sa se desfasuare mai rapid decât varianta prezentata la punctul 2, deoarece optimizer-ul bazei de date va alege un plan de execuție mai eficient dacă ii transmitem de la început că dorim să ștergem două milioane de înregistrări în loc să ștergem de 2000 de ori cate 1000 de înregistrări.
În loc de concluzie: înainte de a demara o astfel de operațiune trebuie sa analizați cu atenție ce va presupune și sa va luați toate masurile în cazul în care aceasta va trebui oprita. Înainte de a începe ar trebui sa aveți răspunsul următoarelor întrebări:
- există un interval orar în care utilizatorii nu accesează baza de date?
- în cat timp trebuie să fie șterse înregistrările?
- avem suficient spațiu pe storage?
- sunteți absolut siguri ca datele trebuie șterse definitv din baza de date? de preferat să faceți un backup în cazul în care se contramandează operațiunea cerută