使用批量收集的显式游标与隐式游标:任何性能问题?
Explicit cursors using bulk collect vs. implicit cursors: any performance issues?
在 Oracle Magazine 的一篇较早的文章中(现在在线为 On Cursor FOR Loops)Steven Feuerstein 展示了使用 bulk collect
显式 cursor for loops
的优化(在线文章中的列表 4):
DECLARE
CURSOR employees_cur is SELECT * FROM employees;
TYPE employee_tt IS TABLE OF employees_cur%ROWTYPE INDEX BY PLS_INTEGER;
l_employees employee_tt;
BEGIN
OPEN employees_cur;
LOOP
FETCH employees_cur BULK COLLECT INTO l_employees LIMIT 100;
-- process l_employees using pl/sql only
EXIT WHEN employees_cur%NOTFOUND;
END LOOP;
CLOSE employees_cur;
END;
我知道 bulk collect
提高了性能,因为 SQL 和 PL/SQL 之间的上下文切换较少。
我的问题是关于隐式 cursor for loops
:
BEGIN
FOR S in (SELECT * FROM employees)
LOOP
-- process current record of S
END LOOP;
END;
每个记录的每个循环中是否有上下文切换?问题与显式游标相同还是以某种方式优化了 "behind the scene"?使用带有批量收集的显式游标重写代码会更好吗?
是的,即使你的 -- process current record of S
包含纯 SQL 而没有 PL/SQL 你有上下文切换,因为 FOR ... LOOP
是 PL/SQL 但查询是SQL.
只要有可能,您应该更喜欢使用单个 SQL 语句处理数据(还可以考虑 MERGE,而不仅仅是 DELETE、UPDATE、INSERT),在大多数情况下,它们比一行更快-逐行处理。
请注意,如果您通过 l_employees
进行循环并为每条记录执行 DLL,您将不会获得任何性能。
LIMIT 100
没什么用。一次只处理 100 行几乎与逐行处理相同 - Oracle 在具有 64K 内存的 Z80 上不运行。
从 Oracle 10g 开始,优化 PL/SQL 编译器可以自动将 FOR 循环转换为默认数组大小为 100 的 BULK COLLECT 循环。
所以通常不需要将隐式 FOR 循环转换为 BULK COLLECT 循环。
但有时您可能想改用 BULK COLLECT。例如,如果每次提取 100 行的默认数组大小不满足您的要求,或者如果您更愿意更新集合内的数据。
Tom Kyte 回答了同样的问题。您可以在这里查看:Cursor FOR loops optimization in 10g
在 Oracle Magazine 的一篇较早的文章中(现在在线为 On Cursor FOR Loops)Steven Feuerstein 展示了使用 bulk collect
显式 cursor for loops
的优化(在线文章中的列表 4):
DECLARE
CURSOR employees_cur is SELECT * FROM employees;
TYPE employee_tt IS TABLE OF employees_cur%ROWTYPE INDEX BY PLS_INTEGER;
l_employees employee_tt;
BEGIN
OPEN employees_cur;
LOOP
FETCH employees_cur BULK COLLECT INTO l_employees LIMIT 100;
-- process l_employees using pl/sql only
EXIT WHEN employees_cur%NOTFOUND;
END LOOP;
CLOSE employees_cur;
END;
我知道 bulk collect
提高了性能,因为 SQL 和 PL/SQL 之间的上下文切换较少。
我的问题是关于隐式 cursor for loops
:
BEGIN
FOR S in (SELECT * FROM employees)
LOOP
-- process current record of S
END LOOP;
END;
每个记录的每个循环中是否有上下文切换?问题与显式游标相同还是以某种方式优化了 "behind the scene"?使用带有批量收集的显式游标重写代码会更好吗?
是的,即使你的 -- process current record of S
包含纯 SQL 而没有 PL/SQL 你有上下文切换,因为 FOR ... LOOP
是 PL/SQL 但查询是SQL.
只要有可能,您应该更喜欢使用单个 SQL 语句处理数据(还可以考虑 MERGE,而不仅仅是 DELETE、UPDATE、INSERT),在大多数情况下,它们比一行更快-逐行处理。
请注意,如果您通过 l_employees
进行循环并为每条记录执行 DLL,您将不会获得任何性能。
LIMIT 100
没什么用。一次只处理 100 行几乎与逐行处理相同 - Oracle 在具有 64K 内存的 Z80 上不运行。
从 Oracle 10g 开始,优化 PL/SQL 编译器可以自动将 FOR 循环转换为默认数组大小为 100 的 BULK COLLECT 循环。
所以通常不需要将隐式 FOR 循环转换为 BULK COLLECT 循环。
但有时您可能想改用 BULK COLLECT。例如,如果每次提取 100 行的默认数组大小不满足您的要求,或者如果您更愿意更新集合内的数据。
Tom Kyte 回答了同样的问题。您可以在这里查看:Cursor FOR loops optimization in 10g