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

时间:2009-06-12 14:44:59

标签: 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

或简单的选择,如:

INSERT INTO BAR(A,
                B,
                C)
        (SELECT A,
                B,
                C
        FROM FOO);

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

7 个答案:

答案 0 :(得分:29)

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

答案 1 :(得分:22)

一般的经验法则是,如果您可以使用单个SQL语句而不是使用PL / SQL来实现,那么您应该这样做。它通常会更有效率。

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

e.g。

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;

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

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

答案 2 :(得分:5)

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

答案 3 :(得分:5)

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

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

答案 4 :(得分:3)

我认为在这个问题中缺少一个重要信息。

您要插入多少条记录?

  1. 如果从1到cca。 10.000然后你应该使用SQL语句(就像他们说它易于理解并且很容易编写)。
  2. 如果来自cca。 10.000到cca。 100.000然后你应该使用游标,但你应该添加逻辑来提交每10,000条记录。
  3. 如果来自cca。 100.000到数百万,那么你应该使用批量收集以获得更好的性能。

答案 5 :(得分:0)

您可以使用:

批量收集名为Bulk binding的FOR ALL。

因为PL / SQL forall运算符的速度比简单表插入快30倍。

BULK_COLLECT和Oracle FORALL这两个功能一起称为Bulk Binding。批量绑定是一种PL / SQL技术,而不是执行多个单独的SELECTINSERTUPDATEDELETE语句来从中检索或存储数据表,所有操作都是一次性进行的。这样可以避免在PL / SQL引擎必须传递给SQL引擎,然后返回到PL / SQL引擎时获得的上下文切换,等等,当您单独一次访问一行时。要使用INSERTUPDATEDELETE语句进行批量绑定,请将SQL语句括在PL / SQL FORALL语句中。要使用SELECT语句进行批量绑定,请在BULK COLLECT语句中添加SELECT子句,而不是使用INTO

它提高了性能。

答案 6 :(得分:0)

我都不做每天完全重新加载数据的操作。例如,说我正在加载我的丹佛网站。还有其他一些用于接近实时增量的策略。

我使用的创建表SQL几乎和批量加载一样快 例如,在create table语句下面用于暂存数据,将列转换为所需的正确数据类型:

创建表sales_dataTemp作为选择 将(第1栏设为日期)转换为SALES_QUARTER, (以销售数量计算)为SALES_IN_MILLIONS, .... 从  TABLE1;

此临时表完全反映了我的目标表的结构,该结构按站点进行了分区。 然后,我与DENVER分区进行分区交换,并且有一个新的数据集。