什么更有效率? (SP PL/SQL)
What is more efficient? (SP PL/SQL)
我有一个执行某些事务(插入/更新)的存储过程,想知道这两个选项中的哪一个更有效 运行 "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;
没事吧?或者有更好的方法吗?
选项 #2 肯定更有效,尽管很难说它在您的情况下是否会引人注目。
每个COMMIT
需要少量体力I/O; Oracle 必须确保所有数据都写入磁盘,系统更改号 (SCN) 写入磁盘,可能还有其他我不知道的一致性检查。实际上,多个用户需要大量 COMMIT
才能显着降低数据库速度。发生这种情况时,您可能会看到涉及重做、控制文件等的异常等待事件。
在发出 COMMIT
之前,Oracle 可以在内存中或异步进行更改。这可能会使性能达到 equivalent to an in-memory database.
如 Sylvain Leroux 所建议的,更好的选择是使用单个 MERGE
语句来完全避免该问题。如果处理必须在 PL/SQL 中完成,至少用更简单的游标 FOR 循环替换 OPEN/FETCH 游标语法。游标 FOR 循环将自动批量收集数据,显着提高读取性能。
我有一个执行某些事务(插入/更新)的存储过程,想知道这两个选项中的哪一个更有效 运行 "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;
没事吧?或者有更好的方法吗?
选项 #2 肯定更有效,尽管很难说它在您的情况下是否会引人注目。
每个COMMIT
需要少量体力I/O; Oracle 必须确保所有数据都写入磁盘,系统更改号 (SCN) 写入磁盘,可能还有其他我不知道的一致性检查。实际上,多个用户需要大量 COMMIT
才能显着降低数据库速度。发生这种情况时,您可能会看到涉及重做、控制文件等的异常等待事件。
在发出 COMMIT
之前,Oracle 可以在内存中或异步进行更改。这可能会使性能达到 equivalent to an in-memory database.
如 Sylvain Leroux 所建议的,更好的选择是使用单个 MERGE
语句来完全避免该问题。如果处理必须在 PL/SQL 中完成,至少用更简单的游标 FOR 循环替换 OPEN/FETCH 游标语法。游标 FOR 循环将自动批量收集数据,显着提高读取性能。