sql >> Databasteknik >  >> RDS >> Oracle

hur man hämtar, tar bort, commit från markören

Varför vill du binda dig i omgångar? Det kommer bara att sakta ner din bearbetning. Om det inte finns andra sessioner som försöker ändra raderna du försöker ta bort, vilket verkar problematiskt av andra skäl, skulle det mest effektiva tillvägagångssättet vara att helt enkelt ta bort data med en enda DELETE, dvs.

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

Naturligtvis kan det mycket väl finnas ett mer optimalt sätt att skriva detta beroende på hur frågan bakom din markör är utformad.

Om du verkligen vill eliminera BULK COLLECT (vilket kommer att sakta ner processen avsevärt), kan du använda WHERE CURRENT OF-syntaxen för att göra 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.

Var dock medveten om att eftersom du måste låsa raden (med FOR UPDATE-satsen), kan du inte lägga en commit i loopen. Om du gör en commit släpper du låsen du hade begärt med FÖR UPPDATERING och du kommer att få ett ORA-01002:fel för att hämta ur sekvensen

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

Du kanske inte får ett körtidsfel om du tar bort låsningen och undviker syntaxen WHERE CURRENT OF, tar bort data baserat på värdet/värdena du hämtade från markören. Detta gör dock fortfarande en apportering, vilket är en dålig praxis och radikalt ökar oddsen att du, åtminstone periodvis, kommer att få ett ORA-01555:ögonblicksbild för gammalt fel. Det kommer också att vara smärtsamt långsamt jämfört med den enda SQL-satsen eller alternativet 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.

Naturligtvis måste du också se till att din process är omstartbar ifall du bearbetar någon delmängd av rader och har ett okänt antal interimistiska commits innan processen dör. Om DELETE är tillräckligt för att göra att raden inte längre returneras från din markör, är din process förmodligen redan omstartbar. Men generellt sett är det ett problem om du försöker dela upp en enda operation i flera transaktioner.



  1. Hitta datakällan för en viss tabell - ORACLE

  2. Fungerar Dapper på Mono?

  3. MySQL ERROR 1005:Kan inte skapa tabell (errnr:150)

  4. executemany för MySQLdb-fel för stort antal rader