2011-12-27 90 views
0

我在pl/sql塊中寫了一個遊標。如果它有更多的記錄,這個塊花費很多時間。 如何在沒有光標的情況下編寫此代碼或者是否有其他可以減少時間的替代方法? 是否有任何替代查詢來執行插入到一個表中並使用單個查詢從另一個表中刪除?如何在不使用Cursor的情況下編寫以下pl/sql塊?

DECLARE 
     MDLCursor SYS_REFCURSOR; 
    BEGIN 
     open MDLCursor for 
     select dc.dest_id, dc.digits, dc.Effectivedate, dc.expirydate 
      from DialCodes dc 
     INNER JOIN MDL d 
      ON dc.Dest_ID = d.Dest_ID 
      AND d.PriceEntity = 1 
      join sysmdl_calltypes s 
      on s.call_type_id = v_CallType_ID 
      and s.dest_id = dc.Dest_ID 
      and s.call_type_id not in 
       (select calltype_id from ignore_calltype_for_routing) 
     order by length(dc.digits) desc, dc.digits desc; 
     loop 
     fetch MDLCursor 
      into v_mdldest_id, v_mdldigits, v_mdlEffectiveDate, v_mdlExpDate; 
     insert into tt_pendingcost_temp 
      (Dest_ID, 
      Digits, 
      CCASDigits, 
      Destination, 
      tariff_id, 
      NewCost, 
      Effectivedate, 
      ExpiryDate, 
      previous, 
      Currency) 
      select v_mdldest_id, 
       Digits, 
       v_mdldigits, 
       Destination, 
       tariff_id, 
       NewCost, 
       Effectivedate, 
       ExpiryDate, 
       previous, 
       Currency 
      FROM tt_PendingCost 
      where substr(Digits, 1, 2) = substr(v_MDLDigits, 1, 2) 
      and instr(Digits, v_MDLDigits) = 1 
      and v_mdlEffectiveDate <= effectivedate 
      and (v_mdlExpDate > effectivedate or v_mdlExpDate is null); 
     if SQL%ROWCOUNT > 0 then 
      delete FROM tt_PendingCost 
      where substr(Digits, 1, 2) = substr(v_MDLDigits, 1, 2) 
      and instr(Digits, v_MDLDigits) = 1 
      and v_mdlEffectiveDate <= effectivedate 
      and (v_mdlExpDate > effectivedate or v_mdlExpDate is null); 
     end if; 
     exit when MDLCursor%NOTFOUND; 
     end loop; 
     close MDLCursor; 
    END; 
+0

'td_PendingCost'的主鍵是否有'Dest_ID'?這將提供一種改善程序性能的方法。 – APC 2011-12-29 23:18:35

回答

5

我沒有你的表格和你的數據,所以我只能猜測幾件事會讓你放慢速度。

首先,光標中使用的查詢中有一個ORDER BY子句。如果這個查詢返回很多行,那麼Oracle必須先取回所有行並將它們排序,然後才能返回第一行。如果這個查詢通常會返回很多結果,並且您並不特別需要它來返回排序結果,那麼如果您放棄ORDER BY,則可能會發現您的PL/SQL塊的速度有點提升。這樣,您就可以開始從遊標中獲取結果,而無需獲取所有結果,將它們存儲在某個地方並首先對其進行排序。

其次,下面是你INSERT INTO ... SELECT ...DELETE FROM ...語句使用的WHERE條款:

where substr(Digits, 1, 2) = substr(v_MDLDigits, 1, 2) 
     and instr(Digits, v_MDLDigits) = 1 
     and v_mdlEffectiveDate <= effectivedate 
     and (v_mdlExpDate > effectivedate or v_mdlExpDate is null); 

我不知道甲骨文如何能夠有效使用索引與任何條件。因此每次都必須進行全表掃描。

最後兩個條件似乎是合理的,似乎沒有什麼可以與他們完成。我想專注於前兩個條件,因爲我認爲他們有更多的改進空間。

的四個條件的第二個是

instr(Digits, v_MDLDigits) = 1 

此條件成立當且僅當Digits打頭的v_MDLDigits內容。寫這更好的辦法是

Digits LIKE v_MDLDigits || '%' 

在這種情況下,而不是使用INSTRLIKE的好處是,Oracle可以使用LIKE時使用索引。如果您在Digits列中有索引,則Oracle可以將其用於此查詢。然後,Oracle將能夠專注於以v_MDLDigits中的數字開頭的那些行,而不是執行全表掃描。

第一的四個條件是:

substr(Digits, 1, 2) = substr(v_MDLDigits, 1, 2) 

如果v_MDLDigits具有長度爲至少2,和中的所有條目Digits列也有長度至少爲2,則由於這是暗示該條件是多餘在前一個我們看過。

我不知道爲什麼你會有這樣的條件。我能想到爲什麼你可能會遇到這種情況的唯一原因是你的功能索引substr(Digits, 1, 2)。如果沒有,我會試圖完全刪除這個substr條件。

我不認爲遊標是什麼讓這個過程運行緩慢,並沒有單一的聲明,我知道可以插入到一個表中,並從另一個表中刪除。爲了加快這個過程,我想你只需要調整一下查詢。

+0

感謝您的回覆。 – 2011-12-27 16:38:29

相關問題