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

wie man vom Cursor holt, löscht, festschreibt

Warum möchten Sie in Stapeln festschreiben? Das wird Ihre Verarbeitung nur verlangsamen. Sofern nicht andere Sitzungen versuchen, die zu löschenden Zeilen zu ändern, was aus anderen Gründen problematisch erscheint, wäre der effizienteste Ansatz, die Daten einfach mit einem einzigen DELETE zu löschen, d. h.

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

Natürlich kann es eine optimalere Schreibweise geben, je nachdem, wie die Abfrage hinter Ihrem Cursor gestaltet ist.

Wenn Sie das BULK COLLECT wirklich eliminieren möchten (was den Prozess erheblich verlangsamt), können Sie die WHERE CURRENT OF-Syntax verwenden, um das DELETE auszuführen

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.

Beachten Sie jedoch, dass Sie keinen Commit in die Schleife einfügen können, da Sie die Zeile sperren müssen (mit der FOR UPDATE-Klausel). Ein Commit würde die Sperren freigeben, die Sie mit FOR UPDATE angefordert hatten, und Sie erhalten einen ORA-01002:Fehler beim Abrufen außerhalb der Reihenfolge

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

Sie erhalten möglicherweise keinen Laufzeitfehler, wenn Sie die Sperre entfernen und die WHERE CURRENT OF-Syntax vermeiden, indem Sie die Daten basierend auf den Werten löschen, die Sie vom Cursor abgerufen haben. Dies führt jedoch immer noch zu einem Abruf über Commit hinweg, was eine schlechte Praxis ist und die Wahrscheinlichkeit radikal erhöht, dass Sie zumindest zeitweise den Fehler ORA-01555:Snapshot too Old erhalten. Es wird auch im Vergleich zur einzelnen SQL-Anweisung oder der Option BULK COLLECT schmerzhaft langsam sein.

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.

Natürlich müssen Sie auch sicherstellen, dass Ihr Prozess neu gestartet werden kann, falls Sie eine Teilmenge von Zeilen verarbeiten und eine unbekannte Anzahl von Zwischen-Commits haben, bevor der Prozess stirbt. Wenn der DELETE ausreicht, um zu bewirken, dass die Zeile nicht mehr von Ihrem Cursor zurückgegeben wird, ist Ihr Prozess wahrscheinlich bereits neu startbar. Aber im Allgemeinen ist das ein Problem, wenn Sie versuchen, einen einzelnen Vorgang in mehrere Transaktionen aufzuteilen.