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

come recuperare, eliminare, eseguire il commit dal cursore

Perché vuoi impegnarti in batch? Questo rallenterà solo la tua elaborazione. A meno che non ci siano altre sessioni che stanno cercando di modificare le righe che stai tentando di eliminare, il che sembra problematico per altri motivi, l'approccio più efficiente sarebbe semplicemente eliminare i dati con un singolo DELETE, ad es.

DELETE FROM uiv_response_income uri
 WHERE EXISTS( 
    SELECT 1
      FROM (<<bulk_delete_dup query>>) bdd
     WHERE bdd.rowid = uri.rowid
  )

Naturalmente, potrebbe esserci un modo più ottimale per scriverlo a seconda di come è progettata la query dietro il cursore.

Se vuoi davvero eliminare il BULK COLLECT (che rallenterà sostanzialmente il processo), puoi usare la sintassi WHERE CURRENT OF per eseguire DELETE

SQL> create table foo
  2  as
  3  select level col1
  4    from dual
  5  connect by level < 10000;

Table created.

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo for update;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where current of c1;
 10    end loop;
 11* end;
SQL> /

PL/SQL procedure successfully completed.

Tieni presente, tuttavia, che poiché devi bloccare la riga (con la clausola FOR UPDATE), non puoi inserire un commit nel ciclo. Fare un commit rilascerebbe i blocchi che avevi richiesto con FOR UPDATE e otterrai un ORA-01002:errore di recupero della sequenza

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo for update;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where current of c1;
 10      commit;
 11    end loop;
 12* end;
SQL> /
declare
*
ERROR at line 1:
ORA-01002: fetch out of sequence
ORA-06512: at line 7

Potresti non ricevere un errore di runtime se rimuovi il blocco ed eviti la sintassi WHERE CURRENT OF, eliminando i dati in base ai valori che hai recuperato dal cursore. Tuttavia, questo sta ancora eseguendo un recupero attraverso il commit che è una pratica scadente e aumenta radicalmente le probabilità che tu, almeno a intermittenza, otterrai un ORA-01555:snapshot troppo vecchio. Sarà anche dolorosamente lento rispetto alla singola istruzione SQL o all'opzione BULK COLLECT.

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where col1 = l_rowtype.col1;
 10      commit;
 11    end loop;
 12* end;
SQL> /

PL/SQL procedure successfully completed.

Ovviamente, devi anche assicurarti che il tuo processo sia riavviabile nel caso in cui elabori un sottoinsieme di righe e abbia un numero sconosciuto di commit provvisori prima che il processo muoia. Se il DELETE è sufficiente per far sì che la riga non venga più restituita dal cursore, probabilmente il tuo processo è già riavviabile. Ma in generale, questo è un problema se provi a suddividere una singola operazione in più transazioni.