我有一个执行某些事务(插入/更新)的存储过程,并希望知道这两个选项中哪一个更有效地运行“COMMIT”:
选项1:
BEGIN
OPEN myCursor;
LOOP
FETCH myCursor INTO AUX_ID, AUX_VAR1, AUX_VAR2;
EXIT WHEN myCursor%NOTFOUND;
SELECT count(*) INTO myCount FROM myTable WHERE code = AUX_ID;
IF myCount > 0 THEN
UPDATE myTable
SET VAR1 = AUX_VAR1, VAR2 = AUX_VAR2
WHERE code = AUX_ID_BD;
COMMIT;
ELSE
INSERT INTO myTable(code, VAR1, VAR2)
VALUES(AUX_ID, AUX_VAR1, AUX_VAR2)
COMMIT;
END IF;
END LOOP;
CLOSE myCursor;
END;
或选项2:
BEGIN
OPEN myCursor;
LOOP
FETCH myCursor INTO AUX_ID, AUX_VAR1, AUX_VAR2;
EXIT WHEN myCursor%NOTFOUND;
SELECT count(*) INTO myCount FROM myTable WHERE code = AUX_ID;
IF myCount > 0 THEN
UPDATE myTable
SET VAR1 = AUX_VAR1, VAR2 = AUX_VAR2
WHERE code = AUX_ID_BD;
ELSE
INSERT INTO myTable(code, VAR1, VAR2)
VALUES(AUX_ID, AUX_VAR1, AUX_VAR2)
END IF;
END LOOP;
COMMIT;
CLOSE myCursor;
END;
没关系?还是有更好的方法?
答案 0 :(得分:3)
选项#2肯定更有效率,虽然在你的情况下很难判断它是否会引人注意。
每个COMMIT
需要少量的物理I / O; Oracle必须确保将所有数据写入磁盘,将系统更改号(SCN)写入磁盘,并且可能还有其他一些我不知道的一致性检查。实际上,来自多个用户需要大量COMMIT
来显着减慢数据库的速度。当发生这种情况时,您可能会看到涉及REDO,控制文件等的异常等待事件。
在发出COMMIT
之前,Oracle可以在内存中或异步进行更改。这可能会使性能为equivalent to an in-memory database。
更好的选择是完全通过使用单个MERGE
语句来避免这个问题,正如Sylvain Leroux建议的那样。如果必须在PL / SQL中完成处理,至少用更简单的游标FOR-loop替换OPEN / FETCH游标语法。游标FOR循环将自动批量收集数据,从而显着提高读取性能。