なぜバッチでコミットしたいのですか?それはあなたの処理を遅くするだけです。削除しようとしている行を変更しようとしている他のセッションがない限り、他の理由で問題があるように思われますが、最も効率的なアプローチは、1回のDELETEでデータを削除することです。
DELETE FROM uiv_response_income uri
WHERE EXISTS(
SELECT 1
FROM (<<bulk_delete_dup query>>) bdd
WHERE bdd.rowid = uri.rowid
)
もちろん、カーソルの背後にあるクエリがどのように設計されているかによっては、これを書くためのより最適な方法があるかもしれません。
BULK COLLECTを本当に削除したい場合(プロセスが大幅に遅くなります)、WHERECURRENTOF構文を使用して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.
ただし、(FOR UPDATE句を使用して)行をロックする必要があるため、ループにコミットを入れることはできないことに注意してください。コミットを実行すると、FOR UPDATEで要求したロックが解放され、ORA-01002:フェッチアウトオブシーケンスエラーが発生します
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
ロックを解除してWHERECURRENTOF構文を回避し、カーソルからフェッチした値に基づいてデータを削除すると、ランタイムエラーが発生しない場合があります。ただし、これはまだコミット全体でフェッチを実行しているため、これは不適切な方法であり、少なくとも断続的に、ORA-01555:snapshottoooldエラーが発生する可能性が大幅に高まります。また、単一のSQLステートメントまたはBULKCOLLECTオプションと比較して非常に遅くなります。
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.
もちろん、行のサブセットを処理し、プロセスが終了する前に不明な数の中間コミットがある場合に備えて、プロセスが再起動可能であることも確認する必要があります。 DELETE
の場合 行がカーソルから戻されなくなるには十分です。プロセスはおそらくすでに再起動可能です。ただし、一般に、単一の操作を複数のトランザクションに分割しようとすると、それが問題になります。