批量插入Oracle数据库:哪个更好:FOR Cursor循环还是简单选择?

Sat*_*hat 23 sql oracle plsql

哪个是批量插入Oracle数据库的更好选择?一个FOR Cursor循环就像

DECLARE
   CURSOR C1 IS SELECT * FROM FOO;
BEGIN
   FOR C1_REC IN C1 LOOP
   INSERT INTO BAR(A,
                B,
                C)
          VALUES(C1.A,
                 C1.B,
                 C1.C);
   END LOOP;
END
Run Code Online (Sandbox Code Playgroud)

或简单的选择,如:

INSERT INTO BAR(A,
                B,
                C)
        (SELECT A,
                B,
                C
        FROM FOO);
Run Code Online (Sandbox Code Playgroud)

任何一个特定原因要么更好?

Jos*_*ein 30

我建议使用Select选项,因为游标需要更长时间.
对于必须修改查询的任何人来说,使用Select也更容易理解

  • +1.第二个选项也更简洁,不需要编译/执行PL/SQL块. (6认同)

Jef*_*emp 22

一般的经验法则是,如果您可以使用单个SQL语句而不是使用PL/SQL来执行此操作,则应该这样做.它通常会更有效率.

但是,如果需要添加更多过程逻辑(出于某种原因),则可能需要使用PL/SQL,但是应该使用批量操作而不是逐行处理.(注意:在Oracle 10g及更高版本中,您的FOR循环将自动使用BULK COLLECT一次获取100行;但是您的insert语句仍将逐行完成).

例如

DECLARE
   TYPE tA IS TABLE OF FOO.A%TYPE INDEX BY PLS_INTEGER;
   TYPE tB IS TABLE OF FOO.B%TYPE INDEX BY PLS_INTEGER;
   TYPE tC IS TABLE OF FOO.C%TYPE INDEX BY PLS_INTEGER;
   rA tA;
   rB tB;
   rC tC;
BEGIN
   SELECT * BULK COLLECT INTO rA, rB, rC FROM FOO;
   -- (do some procedural logic on the data?)
   FORALL i IN rA.FIRST..rA.LAST
      INSERT INTO BAR(A,
                      B,
                      C)
      VALUES(rA(i),
             rB(i),
             rC(i));
END;
Run Code Online (Sandbox Code Playgroud)

以上功能可以最大限度地减少SQL和PL/SQL之间的上下文切换.Oracle 11g还具有对记录表的更好支持,因此您不必为每列都有单独的PL/SQL表.

此外,如果数据量非常大,则可以更改代码以批量处理数据.


小智 5

如果您的回滚段/撤消段可以容纳事务的大小,那么选项2更好.如果您没有所需的回滚容量并且必须将大插入分解为较小的提交,那么选项1非常有用,因此您不会获得回滚/撤消段太小的错误.


Sco*_*ank 5

像你的第二个选项一样简单的插入/选择是更可取的.对于第一个选项中的每个插入,您需要从pl/sql到sql的上下文切换.使用trace/tkprof运行每个并检查结果.

如果像迈克尔提到的那样,你的回滚无法处理声明,那么让你的dba给你更多.磁盘很便宜,而在多次传递中插入数据所产生的部分结果可能非常昂贵.(插入几乎没有撤消.)