在Oracle杂志的较旧文章(现在在线上为webpart example)中,Steven Feuerstein使用cursor for loops
(针对在线文章中的第4条)显示了对显式bulk collect
的优化:
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;
每个记录的每个循环中都有上下文切换吗?问题与显式光标相同还是在“幕后”进行了某种优化?使用带有批量收集的显式游标重写代码会更好吗?
答案 0 :(得分:2)
从Oracle 10g开始,优化的PL / SQL编译器可以自动将FOR LOOPs转换为默认数组大小为100的BULK COLLECT循环。
因此,通常不需要将隐式FOR循环转换为BULK COLLECT循环。
但是有时您可能想使用BULK COLLECT。例如,如果默认的每次读取100行的数组大小不能满足您的要求,或者您希望更新集中的数据。
汤姆·凯特(Tom Kyte)回答了同样的问题。您可以在此处检查它:Cursor FOR loops optimization in 10g
答案 1 :(得分:0)
是的,即使您的-- process current record of S
包含纯SQL而没有PL / SQL,您也可以进行上下文切换,因为FOR ... LOOP
是PL / SQL但查询是SQL。
只要有可能,您应该更喜欢使用单个SQL语句处理数据(还考虑MERGE,不仅是DELETE,UPDATE和INSERT),在大多数情况下,它们比逐行处理要快。 / p>
请注意,如果通过l_employees
循环并为每条记录执行DLL,则不会获得任何性能。
LIMIT 100
毫无用处。一次只处理100行几乎与一对一处理几乎相同-Oracle不能在具有64K内存的Z80上运行。