2010-04-20 93 views
4

我們一直在使用臨時表來存儲pl/sql存儲過程中的中間結果。任何人都可以分辨通過pl/sql執行批量收集插入與普通SQL插入之間是否存在性能差異。查詢性能差異pl/sql插入和純SQL插入

插入到表名稱] [選擇查詢返回的數據量龐大]

光標爲[選擇查詢返回的數據量龐大]

打開的遊標

取光標批量收集到集合中

使用FORALL執行插入操作

以上兩個選項哪一個最好插入大量的臨時數據?

+0

我認爲兩件事會增加討論的重量 1.我們沒有執行任何中間處理。只需簡單地選擇並插入。 2.查詢的選擇部分只有很少的綁定變量。你認爲這對緩存遊標查詢的選擇部分的計劃可能會帶來一些好處。 – Prakash 2010-04-20 06:22:08

+0

如果查詢以不同的值運行,它們應該幾乎總是作爲綁定變量傳遞。 但是,如果'SELECT'需要很長時間,其性能可能不會受到太大影響,儘管由於解析階段相對較短 - 但使用綁定變量將減少對共享池的影響,這有助於減少整體從所有必須進行的解析中加載到服務器上。 但是這種考慮與簡單的SELECT和BULK COLLECT的性能問題是正交的。 – 2010-04-20 07:08:23

+0

我想確保離開綁定變量的解析時間優勢不會因直接插入而丟失。這是事務性系統,許多用戶運行報告,因此臨時表的人口經常出現。我不是比較簡單的選擇,它是一個複雜的帶有綁定變量的選擇查詢。與散裝收集相比,你們是否仍然認爲插入物可能會更快? – Prakash 2010-04-20 09:58:49

回答

6

您的問題的一些實驗數據(Oracle 9。2)

散裝收集

DECLARE 
    TYPE t_number_table IS TABLE OF NUMBER; 
    v_tab t_number_table; 
BEGIN 
    SELECT ROWNUM 
    BULK COLLECT INTO v_tab 
    FROM dual 
    CONNECT BY LEVEL < 100000; 

    FORALL i IN 1..v_tab.COUNT 
    INSERT INTO test VALUES (v_tab(i)); 
END; 
/
-- 2.6 sec 

插入

-- test table 
CREATE global TEMPORARY TABLE test (id number) 
ON COMMIT preserve ROWS; 

BEGIN 
    INSERT INTO test 
    SELECT ROWNUM FROM dual 
    CONNECT BY LEVEL < 100000; 
END; 
/
-- 1.4 sec 

直接路徑插入 http://download.oracle.com/docs/cd/B10500_01/server.920/a96524/c21dlins.htm

BEGIN 
    INSERT /*+ append */ INTO test 
    SELECT ROWNUM FROM dual 
    CONNECT BY LEVEL < 100000; 
END; 
/
-- 1.2 sec 
+0

+1。感謝您用一些證明來支持我的懷疑。 – Rene 2010-04-20 08:40:24

+0

對於清晰和經過測試的數據+1(以及使用雙重:)) – Unreason 2010-04-20 12:32:54

+0

這是一個太小的數據集,無法進行比較。 – 2011-06-30 13:10:28

2

插入選擇肯定會更快。跳過首先將數據存儲在集合中的開銷。

3

這取決於您爲填充中間結果所做的工作的性質。如果工作可以在INSERT的SELECT語句中相對簡單地完成,那麼通常會更好。但是,如果您有一些複雜的中間邏輯,使用批量收集/綁定可以更容易(從代碼維護角度)批量提取和插入數據。在某些情況下,它甚至可能會更快。當查詢是通過自身運行由INSERT INTO x SELECT ...使用有時會到使用完全不同的查詢計劃(例如在PL/SQL顯式遊標):

有一點要非常小心注意。在比較性能時,您需要考慮到這一點。

+0

已經更新了我的問題和幾條評論。謝謝btw您的迴應。 – Prakash 2010-04-20 06:23:54

-3

我建議使用PL \ SQL顯式遊標,您只需要在爲遊標分配的私有工作區執行任何DML操作。這在高峯時段不會影響數據庫服務器的性能

+0

-1您需要更清楚地說明這一點 - 「爲光標分配的私人工作空間」是什麼意思?「高峯時間」如何進入? – 2010-04-20 07:10:58

+0

對於大數據量使用批量採集肯定會使用PGA內存,這是內存,不可用於服務器上的其他進程。 – 2010-04-20 07:19:43

0

當我們明確聲明遊標時,oracle將在我們的RAM中分配一個私有SQL工作區。當你有選擇語句返回多行時,將作爲ACTIVE SET從表或視圖複製到私有SQL工作區。它的大小是符合您的搜索條件的行數。一旦光標打開,您的指針將被放置在ACTIVE SET的第一行。在這裏你可以執行DML。例如,如果您執行一些更新操作。它將更新工作區中行中的所有更改,而不是直接更新表中的行。所以每次我們需要更新時都不會使用表格。它會一次訪問工作區域,然後在執行操作之後,所有操作都會執行一次更新。這減少了數據庫和用戶之間的輸入/輸出數據傳輸。

2

asktomhome fame的Tom Kyte更加堅定地回答了這個問題。如果你願意做一些搜索,你可以找到問題和他的回答,這些問題包含詳細的測試結果和解釋。他顯示plsql遊標與plsql批量收集包括週期性提交的影響,而sql插入爲select。

插入作爲選擇贏得手下所有時間和甚至適度的數據集的差異是戲劇性的。

這就是說。之前對中介計算的複雜性做了評論。我可以想到三種情況,這是相關的。

1)如果計算需要超出Oracle數據庫範圍,那麼顯然一個簡單的insert作爲select並不能解決問題。

2)如果解決方案需要使用PLSQL函數調用,則上下文切換可能會導致您的查詢中斷,並且使用plsql調用plsql函數可能會獲得更好的結果。 PLSQl被稱爲SQL,但不是相反。因此,從SQL調用PLSQL非常昂貴。

3)如果計算使sql代碼非常難以閱讀,即使速度可能較慢,但由於其他原因,plsql批量收集解決方案可能會更好。

祝你好運。