有没有办法在指定提交计数时执行INSERT INTO SELECT语句?

时间:2012-04-16 15:07:20

标签: oracle oracle11g

DB:Oracle 11g

有没有办法做以下事情:

INSERT INTO T1
    (V1, V2)
COMMIT EVERY X
AS
SELECT (V1, V2) FROM T2;

我知道如何循环游标,但我正在寻找更精简的东西。

PL / SQL很好,但没有循环 使用SQL提示也很好。

如果这只是oracle无法处理的事情,那么就会产生悲伤(大部分时间我都很好奇,因为我已经有了另一种方法)。

注意:该应用程序有数千亿条记录。每天创造数百万。 INSERT INTO SELECT不适用于如此大的数据集。特别是当有大量的并行运行时。

3 个答案:

答案 0 :(得分:8)

Oracle不允许声明进行临时提交,不。这样做会违反ACID数据库的基本属性。如果语句在第N行失败会怎么样? Oracle无法回滚先前提交的行。它不知道哪些行已处理,哪些行未处理。因此,您的声明将部分成功,您的数据库将处于未知状态。使用关系数据库的一个主要好处是可以完全避免这种结果。

为什么你想首先进行临时提交?这将使您的代码变慢并导致您使用更多资源。它会强制你编写一堆代码来使你的进程可以重新启动(即你必须跟踪哪些行已被处理,哪些没有,以便你可以回滚部分完成的更改,或者如果失败则重新启动进程在中间)。它会让您的代码更难以测试。几乎没有理由做临时提交。

答案 1 :(得分:5)

Oracle不提供这样的SQL构造。使用带游标的PL / SQL和FORALL语句可以为你做...但是:

甲骨文没有提供这样的悲伤是件好事。 Oracle是一个基于ACID原则的RDBMS。我代表隔离,在Oracle中,默认为READ COMMITTED。这意味着其他并发事务无法在中途看到您的事务。它可以防止其他会话看到不一致的数据。使用RDBMS的基石之一。

这给我们带来了最重要的问题:为什么你会想要这样的结构?

我希望不要担心“大”交易。

答案 2 :(得分:0)

我没有检查它,但也许用bulk inserts你可以做到这一点:

DECLARE
  TYPE ARRAY IS TABLE OF T2%ROWTYPE;
  l_data ARRAY;
  x NUMBER;

  CURSOR c IS SELECT V1, V2 FROM T2;

BEGIN
    OPEN c;
    LOOP
    FETCH c BULK COLLECT INTO l_data LIMIT x;

    FORALL i IN 1..l_data.COUNT
    INSERT INTO T1 VALUES l_data(i);

    COMMIT;

    EXIT WHEN c%NOTFOUND;
    END LOOP;
    CLOSE c;
END;

但作为Justin Cave,WHY ???