2011-12-27 4 views
0

私はpl/sqlブロックにカーソルを書きました。このブロックは、それ以上のレコードがある場合は時間がかかります。 カーソルなしでこれを書く方法または時間を短縮する他の方法がありますか? 1つのテーブルに挿入し、1つのクエリを使用して別のテーブルから削除する代替クエリはありますか?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

'Dest_ID'は' tt_PendingCost'の主キーですか?これは、手順のパフォーマンスを向上させる方法を提供します。 – APC

答えて

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); 

私はOracleはこれらの条件のいずれかにインデックスを有効に活用することができますどのように表示されません。したがって、毎回フルテーブルスキャンを実行する必要があります。

最後の2つの条件は妥当と思われ、それらで実行できることはあまりありません。最初の2つの条件に焦点を当てたいのですが、改善の余地があると思います。

4つの条件の第二は

instr(Digits, v_MDLDigits) = 1 

あるこの状態は、Digitsv_MDLDigitsの内容で始まる場合にのみ成立します。これを書いてのより良い方法は

Digits LIKE v_MDLDigits || '%' 

代わりINSTRのこの状況でLIKEを使用する利点は、LIKEを使用した場合、Oracleは索引の使用を作ることができるということであるだろう。 Digits列に索引がある場合、Oracleはこの問合せで索引を使用できます。 Oracleは、フル・テーブル・スキャンを実行するのではなく、v_MDLDigitsの数字で始まる行に集中できます。

4つの条件の第一は、次のとおり

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

v_MDLDigitsは長さは少なくとも2であり、Digits列内のすべてのエントリはまた、長さは少なくとも2を持っている場合、それが暗示されているので、この条件は冗長です私たちが見た前のものによって。

なぜこのような状態になるのかわかりません。なぜあなたがこの条件を持っているのかもしれないと思う唯一の理由は、機能的なインデックスがsubstr(Digits, 1, 2)にある場合です。もしそうでなければ、私はこのsubstrの状態を完全に削除したいと思うでしょう。

カーソルがこのプロシージャをゆっくり実行しているとは思わないし、あるテーブルに挿入して別のテーブルから削除できることがわかっている単一のステートメントはありません。この手順を高速化するには、クエリを少し調整する必要があると思います。

+0

ご回答ありがとうございます。 –

関連する問題