0

COMMIT をコード ブロックに入れる方法が適切かどうか疑問に思っていますか? ループが終了したとき、または各insertステートメントの後、またはif elseステートメントの後に配置する必要がありますか?

FOR VAL1 IN (SELECT A.* FROM TABLE_A A) LOOP
 IF VAL1.QTY >= 0 THEN
   INSERT INTO TEMP_TABLE VALUES('MORE OR EQUAL THAN 0');
   COMMIT; /*<-- Should I put this here?*/
   INSERT INTO AUDIT_TABLE VALUE('DATA INSERTED >= 0');
   COMMIT; /*<-- Should I put this here too?*/
 ELSE
   INSERT INTO TEMP_TABLE VALUES ('0');
   COMMIT; /*<-- Should I put this here too?*/
   INSERT INTO AUDIT_TABLE('DATA INSERTED IS 0');
   COMMIT; /*<-- Should I put this here too?*/
 END IF;
/*Or put commit here?*/
END LOOP;

/*Or here??*/
4

3 に答える 3

2

一般に、特にそのループ内のすべての DML の後で、ループ内でコミットすることはお勧めできません。そうすることで、Oracle(LGWR) が REDO ログ ファイルにデータを書き込むように強制され、log file sync待機イベントのために他のセッションがハングする状況に陥る可能性があります。ORA-1555または、元に戻すセグメントがより頻繁にクリアされるため、 直面しています。

DML を論理的な作業単位 (トランザクション) に分割し、その作業単位が完了したときにコミットします。トランザクションの前でも遅すぎても途中でも構いません。これにより、データベースを一貫した状態に保つことができます。たとえば、2 つのinsertステートメントが 1 つの作業単位 (1 つのトランザクション) を形成する場合、それらを個別にではなく、まとめてコミットまたはロールバックするのが理にかなっています。

したがって、一般的に、コミットはできるだけ少なくする必要があります。ループでコミットする必要ある場合は、いくつかのしきい値を導入してください。たとえば、150 行の後に commit を発行するとします。

declare
  l_commit_rows number;

For i in (select * from some_table)
loop
  l_commit_rows := l_commit_rows + 1;
  insert into some_table(..) values(...);
  if mode(l_commit_rows, 150) = 0 
  then
    commit;
  end if;
end loop;
-- commit the rest  
commit;
于 2013-10-28T08:09:50.910 に答える
1

めったに適切ではありません。TEMP_TABLE への挿入は成功したが、AUDIT_TABLE への挿入は失敗したとします。そうすると、自分がどこにいるのかまったくわかりません。さらに、コミットにより、操作の実行にかかる時間が長くなります。

単一のトランザクション内ですべてを実行する方がより一般的です。つまり、LOOP を削除し、単一のステートメントで挿入を実行します。これは、複数テーブルの挿入を使用して行うことができ、次のようになります。

insert
  when ( a.qty >= 0 ) then
     into temp_table values ('MORE OR EQUAL THAN 0')
     into audit_table values ('DATA INSERTED >= 0')
  else
     into temp_table values ('0')
     into audit_table values ('DATA INSERTED IS 0')
select qty from table_a

簡単なルールは、アクションの途中でコミットしないことです。操作を再開する必要がある場合は、自分がどこにいたかを正確に知ることができる必要があります。これは通常、最初に戻ることを意味しますが、そうする必要はありません。たとえば、COMMIT をループの内側で IF ステートメントの外側に配置すると、それが完了したことがわかります。ただし、この操作が完了したことを伝えるためにどこかに書き戻すか、SQL ステートメントを使用してその行を再評価する必要があるかどうかを判断する必要があります。

于 2013-10-28T08:10:44.117 に答える