只是想知道我在代码块中放置COMMIT的方式是否合适?我应该在完成循环或每个插入语句之后或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??*/
答案 0 :(得分:2)
通常,在循环中提交并不是一个好主意,尤其是在该循环中的每个DML之后。这样做会强制oracle(LGWR)在重做日志文件中写入数据,并且可能会因为log file sync
等待事件而导致其他会话挂起。或者面对ORA-1555
,因为将更频繁地清除撤消细分。
将您的DML划分为逻辑工作单元(事务),并在完成该工作单元时提交,而不是在之前,不是太晚或在事务中间。这将允许您使数据库保持一致状态。例如,如果两个insert
语句形成一个工作单元(一个事务),则完全提交或回滚它们是不合理的。
因此,通常情况下,您应该尽可能少地提交。如果必须在循环中提交,请引入一些阈值。比如问题提交之后,比方说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;
答案 1 :(得分:1)
很少适合;说你的插入TEMP_TABLE成功但你插入AUDIT_TABLE失败。然后你根本不知道你在哪里。此外,提交将增加执行操作所需的时间。
在单个交易中执行所有操作更为正常;即删除LOOP并在单个语句中执行插入。这可以通过使用multi-table insert来完成,看起来像这样:
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语句来确定是否需要重新评估该行。
答案 2 :(得分:0)
如果在每个insert语句后插入commit,则数据库将提交插入的每一行。如果在IF语句结束后插入提交,则会发生相同的情况。 (因此两者都会在每个插入的行之后提交)。如果在循环之后给出commit,则在插入所有行之后将进行提交。
循环后提交应该更快,因为它将提交批量数据但是如果你的循环遇到任何错误(比如在处理了50行之后出现错误),那么你的50行也不会被插入。 因此,根据您的要求,您可以在循环之后或之后使用提交