简体   繁体   English

PL / SQL Oracle存储过程循环结构

[英]PL/SQL Oracle Stored Procedure loop structure

Just wondering if the way I put COMMIT in the code block is appropriate or not? 只是想知道我将COMMIT放入代码块的方式是否合适? Should I put them when it finished loop or after each insert statement or after the if else statement? 我应该在结束循环时还是在每个插入语句之后或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??*/

Generally, committing in a loop is not a good idea, especially after every DML in that loop. 通常,在循环中提交不是一个好主意,尤其是在该循环中的每个DML之后。 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. 这样做会强制oracle(LGWR)在重做日志文件中写入数据,并且可能由于log file sync等待事件而使其他会话挂起。 Or facing ORA-1555 because undo segments will be cleared more often. 或面对ORA-1555因为撤消段将被更频繁地清除。

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. 将您的DML划分为逻辑工作单元(事务),并在完成该工作单元时提交,而不是在事务处理之前或之后或事务中间进行提交。 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. 例如,如果两个insert语句构成一个工作单元(一个事务),那么将它们完全分开提交或回滚是有意义的。

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: 例如,之后发出问题,例如说150行:

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;

It is rarely appropriate; 很少适合; say your insert into TEMP_TABLE succeeds but your insert into AUDIT_TABLE fails. 说您插入TEMP_TABLE成功,但插入AUDIT_TABLE失败。 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. 即删除LOOP,然后在单个语句中执行插入操作。 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. 例如,如果要将COMMIT放在循环中但在IF语句之外,则您知道那已经完成。 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. 您必须在某个地方写回信息以告诉您该操作已经完成,或者使用SQL语句确定是否需要重新评估该行。

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. 如果在IF语句结束后插入commit,也会发生同样的情况。 (So both will commit after each inserted row). (因此两者都将在每个插入的行之后提交)。 If commit is given after loop then commit will happen after all rows are inserted. 如果在循环之后给出commit,那么将在插入所有行之后进行提交。

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. 循环后提交应该更快,因为它将提交批量数据,但是如果循环遇到任何错误(例如,在处理了50行之后出现错误),那么也不会插入您的50行。 So according to your requirement u can either use commit after if or after loop 因此,根据您的要求,您可以在if或after循环之后使用commit

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM