2011-12-30 115 views
2

我有一個程序,可以根據日期,對象名稱和代碼來組織一個非常大的表中的一系列事務的第一個,最後一個,最大和最小价格。我還需要交易數量的總和。表中約有30億行,這個過程需要很多天才能運行。我想盡可能地減少這個時間。我在變換表中的不同字段上有一個索引,並在查詢的選定部分查看解釋計劃,正在使用該索引。我樂於接受其他方法的建議。我使用Oracle 11g R2。謝謝。優化Oracle 11g程序

declare 
    cursor c_iter is select distinct dt, obj, cd from trans; 
    r_iter c_iter%ROWTYPE; 
    v_fir number(15,8); 
    v_las number(15,8); 
    v_max number(15,8); 
    v_min number(15,8); 
    v_tot number; 
    begin 
    open c_iter; 
    loop 
     fetch c_iter into r_iter; 
     exit when c_iter%NOTFOUND; 

     select max(fir), max(las) into v_fir, v_las 
     from 
      (select 
       first_value(prc) over (order by seq) as "FIR", 
       first_value(prc) over (order by seq desc) as "LAS" 
       from trans 
       where dt = r_iter.DT and obj = r_iter.OBJ and cd = r_iter.CD); 

      select max(prc), min(prc), sum(qty) into v_max, v_min, v_tot 
      from trans 
      where dt = r_iter.DT and obj = r_iter.OBJ and cd = r_iter.CD; 

      insert into stats (obj, dt, cd, fir, las, max, min, tot) 
      values (r_iter.OBJ, r_iter.DT, r_iter.CD, v_fir, v_las, v_max, v_min, v_tot); 

      commit; 
    end loop; 
    close c_iter; 
end; 

回答

7
alter session enable parallel dml; 

insert /*+ append parallel(stats)*/ 
into stats(obj, dt, cd, fir, las, max, min, tot) 
select /*+ parallel(trans) */ obj, dt, cd 
    ,max(prc) keep (dense_rank first order by seq) fir 
    ,max(prc) keep (dense_rank first order by seq desc) las 
    ,max(prc) max, min(prc) min, sum(qty) tot 
from trans 
group by obj, dt, cd; 

commit; 
  • 一個SQL語句通常比顯著多個SQL語句更快。它們有時需要更多的資源,比如更多的臨時表空間,但是不同的遊標可能已經對磁盤上的整個表進行了整理。
  • 您可能還想啓用並行DML和並行查詢,但取決於您的對象和系統設置,這可能已經發生。 (根據您的資源,這可能不是一件好事,但它通常有助於大量查詢。)
  • 如果SQL寫入大量數據,並行寫入和APPEND應該會提高性能,但這也意味着新的表在下次備份之前不能恢復。 (並行DML會自動使用直接路徑寫,但我通常包括APPEND反正公正的情況下並行工作不正常。)

有很多的考慮,即使是這麼小的查詢,但這次是我會在哪裏開始。

+0

謝謝你這是一個非常優雅的解決方案。我會按照當前的腳本計時,並報告回來。 – 2011-12-30 19:03:40

+0

這個sql在3個小時內運行了3天。我非常驚訝。十分感謝你的幫助。你做諮詢嗎? – 2011-12-31 20:34:40

+0

請注意,並行查詢僅在企業版中許可。這也不是銀彈。 – APC 2012-01-02 10:17:22

2

不實的答案,我想給,但有幾個事情要考慮:

第一是使用bulk collect。但是,由於您使用的是11g,希望這已經爲您自動完成。

你真的需要在每次迭代後提交嗎?我可能是錯的,但我猜這是你最好的時間消費者之一。

最後,+1爲jonearles的答案。 (我不確定是否可以將所有內容寫入單個SQL查詢,但我也會建議這一點。)

+1

可以計數到2k之類,並在每個間隔後提交。 – Alfabravo 2011-12-30 17:08:23

+1

這可能不是一個好主意。承諾打開遊標幾乎肯定會導致ORA-1555錯誤。此外,在這種情況下,在選擇和插入之間沒有發生處理,@jonearles描述的插入...選擇......是明顯的贏家。 – 2011-12-31 19:24:46

0

您可以嘗試使查詢並行運行,合理的Oracle白皮書here。這不是我必須使用自己的Oracle功能,所以我沒有第一手的體驗。您還需要在Oracle服務器上有足夠的可用資源,以允許您運行將創建的並行流程。