2011/11/22

Oracle的Cursor寫法

  在Oracle下使用Update有諸多限制,之前有研究過使用兩個Table進行Update的語法。但是在真正資料量極大及SQL條件極複雜的情況下,常常有做到當機而未完成。後來真正遇到了要使用Update更新約一年份的交易資料時,這種寫法完全是擾人的作法,Update SQL一下去,全公司幾乎不用工作了,系統資源都被我佔用掉了(笑)。

  在學會Cursor語法後,覺得是方便又快速多了,加上有網友詢問使用兩個Table進行Update的語法,所以我就趕緊記錄下來,希望能幫助到有需要的人。





  Cursor的基本語法相當簡單,只要從基本架構去加入條件即可:

declare
 cursor c_rec is //建立一個指標
  [Select SQL]; //將需要Update的資料先篩選出來
 r_rec c_rec%rowtype; //在記憶體中建立一個臨時表來記錄Select出來的資料,使用指標來存取這個表
begin
 for r_rec in c_rec loop //開始把臨時表中的資料讀出來
  [Update SQL]; //對資料進行更新
 end loop;
 commit;
end;


  我用使用兩個Table進行Update的語法來作比較,但先將語法再複雜化一點。

  這一段語法的目的是找出在B表中B2欄位=2時的A表資料,並將A表中的A2欄位更新為B表中的B3內容,A3欄位更新為B表中的B4內容。
Update ( Select A.A2, A.A3
       From A
      Where A.A1 in (Select B.B1
                From A,B
                Where A.A1=B.B1
                 And B.B2='2'))
  Set (A2,A3) = (Select B.B3, B.B4
            From B
           Where A.A1=B.B1
            And B.B2='2')


  使用這種寫法時,如果AB表各有十萬筆,則在Update語法中就會執行十萬筆的比對(如果一對一而已),在Set語法中還會再進行十萬筆資料比對一次,所以相當費時耗資源。如果你還要加上Max、Min、Sum等函數,其效能之差足以讓資料跑上一般Update的十倍以上(我沒實際算過,但依邏輯來講應該就是會非常差)。

  因為效能極差,所以將它改成Cursor來作,這樣的寫法效能較佳,AB表第一次關聯後如果只剩下一千筆資料,那麼從單一表中找出一千筆資料來作事,絕對會比跑上十萬次或更多次來得好。
declare
 cursor c_rec is
  Select A.A1, B.B3, B.B4
   From A,B
   Where A.A1=B.B1
    And B.B2='2';
 r_rec c_rec%rowtype;
begin
 for r_rec in c_rec loop //這邊的迴圈只會跑有寫進臨時表中的資料,也就是Select後的筆數,在這個地方不會再進行一次Select去咬住系統資源作篩選
  update A
    set A2 = r_rec.B3,
      A3 = r_rec.B4
   where 1 = 1
    and A1 = r_rec.A1;
 end loop;
 commit;
end;


  如果你要寫的Update語法相當複雜,那麼可以考慮使用Cursor來簡化。
總結步驟就是兩個:
(1)下Select找出需要被更新、條件值、更新值之類的資料
(2)將Update語法中的Where條件與(1)中的條件作關聯,然後更新過去。


  以上是一點簡單的Cursor寫法,太艱深的我還沒學到(笑)。

沒有留言:

張貼留言