使用批量收集与隐式游标的显式游标:是否存在性能问题?

时间:2019-03-07 06:50:02

标签: oracle for-loop cursor

在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;

每个记录的每个循环中都有上下文切换吗?问题与显式光标相同还是在“幕后”进行了某种优化?使用带有批量收集的显式游标重写代码会更好吗?

2 个答案:

答案 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上运行。