2012-04-16 77 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