2012-04-16 132 views
2

DB:的Oracle 11g有没有办法在指定提交计数时执行INSERT INTO SELECT语句?

有没有办法做到像下面这样:

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

我知道我如何通过游标循环,而是寻找一些更精简。

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

如果这只是甲骨文无法处理的事情,悲伤随之而来(大多数情况下,我只是好奇,因为我已经有另一种方法工作了)。

注意:该应用程序有数千亿记录。数百万是每天创建的。 INSERT INTO SELECT不适用于如此大的数据集。特别是在同时运行同样大的组时。

+0

正如你从答复中看到的那样,通常没有中间提交的共识,我非常同意。不过,我很好奇,为什么你想要一个中间的提交?有什么需要? – Wolf 2012-04-16 15:54:34

+0

你能解释一下“不起作用”吗?数据仓库在加载期间在不同会话中同时执行大量的INSERT ... SELECT语句是相对常见的。 – 2012-04-16 18:57:34

+0

针对我为什么要这样的问题:应用程序有数千亿记录。数据每天数百万次。 INSERT INTO SELECT不适用于如此大的数据集。特别是在同时运行同样大的组时。游标和FORALL也笨重和丑陋。但主要是,我只是好奇。 – ScrappyDev 2012-04-16 18:58:16

回答

8

Oracle不允许声明具有临时提交,否。这样做会违反ACID数据库的基本属性。如果行N上的语句失败会发生什么? Oracle将无法回滚以前提交的行。它不知道哪些行已经被处理,哪些没有被处理。因此,您的声明将部分成功,您的数据库将处于未知状态。使用关系数据库的一个主要好处是避免确切的结果。

为什么你想在第一个地方做临时提交?这会让你的代码变慢,并导致你使用更多的资源。它会迫使你编写一堆代码来使你的进程可以重启(也就是说,你必须跟踪哪些行已经被处理,哪些没有被处理,这样你就可以回滚部分完整的更改或者在失败时重启进程在中间)。这会让你的代码更难测试。做临时提交几乎没有什么好的理由。

+0

我不明白为什么这会违反酸?它只会将语句中的原子单元更改为行。没有理由说Oracle为什么不能处理这个问题(原则上)。当然,这可能还是一个坏主意。 – 2012-04-16 15:18:22

+0

对于几乎相同的答案+1,早5分钟... – 2012-04-16 15:20:22

+1

@JensSchauder - 至少,ACID必须适用于逻辑陈述。如果您开始允许单个SQL语句部分完成并且部分失败,那么数据库将始终存在数据不一致的风险 - 将资金从A转移到B的语句可以成功地将资金从A中移除,但却无法把钱加到B(反之亦然),编写能够正确处理的代码将非常困难。 – 2012-04-16 15:25:43

5

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

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

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

我希望它不怕“大”交易。

+0

硬件限制适用于“恐惧”大“交易”。特别是当有多个会话正在进行时。 – ScrappyDev 2012-04-16 19:04:31

+0

您只需调整大小即可符合您的要求。我仍然需要遇到第一个系统,由于硬件限制,无法调整大小。 – 2012-04-16 20:59:26

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; 

但贾斯汀洞,为什么???

+0

我们已经成功地使用了FORALL,就像我说过的,我很好奇,如果你不做循环就可以做到这一点。 – ScrappyDev 2012-04-16 19:02:36