0

Just wondering if the way I put COMMIT in the code block is appropriate or not? Should I put them when it finished loop or after each insert statement or after the if else statement?

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

Generally, committing in a loop is not a good idea, especially after every DML in that loop. Doing so you force oracle(LGWR) to write data in redo log files and may find yourself in a situation when other sessions hang because of log file sync wait event. Or facing ORA-1555 because undo segments will be cleared more often.

Divide your DMLs into logical units of work (transactions) and commit when that unit of work is done, not before and not too late or in a middle of a transaction. This will allow you to keep your database in a consistent state. If, for example, two insert statements form a one unit of work(one transaction), it makes sense to commit or rollback them altogether not separately.

So, generally, you should commit as less as possible. If you have to commit in a loop, introduce some threshold. For instance issue commit after, let say 150 rows:

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

It is rarely appropriate; say your insert into TEMP_TABLE succeeds but your insert into AUDIT_TABLE fails. You then don't know where you are at all. Additionally, commits will increase the amount of time it takes to perform an operation.

It would be more normal to do everything within a single transaction; that is remove the LOOP and perform your inserts in a single statement. This can be done by using a multi-table insert and would look something like this:

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

A simple rule is to not commit in the middle of an action; you need to be able to tell exactly where you were if you have to restart an operation. This normally means, go back to the beginning but doesn't have to. For instance, if you were to place your COMMIT inside your loop but outside the IF statement then you know that that has completed. You'd have to write back somewhere to tell you that this operation has been completed though or use your SQL statement to determine whether you need to re-evaluate that row.

于 2013-10-28T08:10:44.117 回答
0

If you insert commit after each insert statement then the database will commit each row inserted. Same will happen if you insert commit after the IF statement ends. (So both will commit after each inserted row). If commit is given after loop then commit will happen after all rows are inserted.

Commit after the loop should work faster as it will commit bulk data but if your loop encounters any error (say after 50 rows are processed there is an error) then your 50 rows also won't be inserted. So according to your requirement u can either use commit after if or after loop

于 2013-10-28T07:56:40.130 回答