sql >> Database >  >> RDS >> Oracle

hoe te halen, verwijderen, commit van cursor

Waarom wil je in batches vastleggen? Dat vertraagt ​​je verwerking alleen maar. Tenzij er andere sessies zijn die proberen de rijen te wijzigen die u probeert te verwijderen, wat om andere redenen problematisch lijkt, zou de meest efficiënte aanpak zijn om de gegevens eenvoudigweg te verwijderen met een enkele DELETE, d.w.z.

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

Natuurlijk kan er een meer optimale manier zijn om dit te schrijven, afhankelijk van hoe de query achter uw cursor is ontworpen.

Als u de BULK COLLECT echt wilt verwijderen (wat het proces aanzienlijk zal vertragen), kunt u de syntaxis WHERE CURRENT OF gebruiken om de DELETE

uit te voeren.
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.

Houd er echter rekening mee dat, aangezien je de rij moet vergrendelen (met de FOR UPDATE-clausule), je geen commit in de lus kunt plaatsen. Als u een commit doet, worden de vergrendelingen die u had aangevraagd met de FOR UPDATE vrijgegeven en krijgt u een ORA-01002:fetch-out of sequence-fout

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

U krijgt mogelijk geen runtime-fout als u de vergrendeling verwijdert en de syntaxis WHERE CURRENT OF vermijdt, waarbij u de gegevens verwijdert op basis van de waarde(n) die u van de cursor hebt gehaald. Dit is echter nog steeds een fetch-cross-commit doen, wat een slechte gewoonte is en de kans radicaal vergroot dat je, in ieder geval met tussenpozen, een ORA-01555:snapshot too old-fout krijgt. Het zal ook pijnlijk traag zijn in vergelijking met de enkele SQL-instructie of de BULK COLLECT-optie.

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.

Natuurlijk moet je er ook voor zorgen dat je proces herstartbaar is voor het geval je een subset van rijen verwerkt en een onbekend aantal tussentijdse commits hebt voordat het proces sterft. Als de DELETE voldoende is om ervoor te zorgen dat de rij niet meer wordt geretourneerd door uw cursor, is uw proces waarschijnlijk al herstartbaar. Maar over het algemeen is dat een punt van zorg als u probeert een enkele bewerking op te splitsen in meerdere transacties.



  1. Sets uit een enkele tabel, gegroepeerd op een kolom

  2. een dynamische query bouwen in mysql en golang

  3. Een tabel per rijtype retourneren in PL/pgSQL

  4. Arabische tekstuitvoer php mysql utf-8 conversieprobleem