哪个更好 - 由Bulk Collect填充的游标上的Cursor For Loop或Loop over PLSQL集合?

时间:2013-10-03 10:07:24

标签: sql plsql oracle11g

其中哪一个更具性能。

版本1 使用Cursor For Loop

DECLARE
  total_val number(6);

  CURSOR c1 IS
  SELECT * FROM emp
  ;
BEGIN
  total_val := 0;
  FOR emp_rec IN c1
  LOOP
    total_val := total_val + emp_rec.sal;
  END LOOP;

  DBMS_OUTPUT.PUT_LINE('TOTAL SALARIES: ' || total_val);
END;

版本2 首先使用Bulk Collect将所有行放入PLSQL集合,然后迭代它。

DECLARE
  total_val number(6);

  CURSOR c1 IS
  SELECT * FROM emp
  ;

  TYPE emp_recs_type IS TABLE OF emp%ROWTYPE;
  emp_recs emp_recs_type;
BEGIN
  total_val := 0;

  OPEN c1;
  FETCH c1 BULK COLLECT INTO emp_recs;
  CLOSE c1;

  FOR l_index IN emp_recs.FIRST..emp_recs.LAST
  LOOP
    total_val := total_val + emp_recs(l_index).sal;
  END LOOP;

  DBMS_OUTPUT.PUT_LINE('TOTAL SALARIES: ' || total_val);
END;

请假设Cursor可能返回多行,可能是数十万或更多。

1 个答案:

答案 0 :(得分:2)

找出答案的最佳方法是设置实验并进行尝试。

当然,对于您的示例,最好的代码是:

DECLARE
  total_val number(6);
BEGIN
  SELECT SUM(sal) INTO total_val FROM emp;

  DBMS_OUTPUT.PUT_LINE('TOTAL SALARIES: ' || total_val);
END;

然而,我意识到这只是一个简单的例子!

理论上使用BULK COLLECT应该会更好,但实际上这些天(肯定是在11G中)Oracle无论如何都会以100行的批量隐藏批量提取 - 请参阅this AskTom thread

如果您自己使用BULK COLLECT并且可能存在未指定数量的行,则应使用LIMIT子句,否则可能会遇到内存问题。对于你的例子,这将是:

DECLARE
  total_val number(6);

  CURSOR c1 IS
  SELECT * FROM emp
  ;

  TYPE emp_recs_type IS TABLE OF emp%ROWTYPE;
  emp_recs emp_recs_type;
BEGIN
  total_val := 0;

  OPEN c1;

  LOOP
    FETCH c1 BULK COLLECT INTO emp_recs LIMIT 100;

    EXIT WHEN c1.COUNT = 0;

    FOR l_index IN emp_recs.FIRST..emp_recs.LAST
    LOOP
      total_val := total_val + emp_recs(l_index).sal;
    END LOOP;

  END LOOP;

  DBMS_OUTPUT.PUT_LINE('TOTAL SALARIES: ' || total_val);
  CLOSE c1;
END;