2016-09-09 9 views
1

パラメータを指定してWebサービスをコールし、その解答を解析して値を戻す関数をPL/SQLで作成しました。それはかなりうまくいく。PL/SQLファンクションのINSERT文

ただし、応答が遅くなることがあります。パラメータは通常、すべての可能な値の非常に小さなサブセットであるため、テーブルに回答をキャッシュするという考えがありました。 機能は、私はこの機能を試してみました次

CREATE OR REPLACE FUNCTION myfct(p1 IN VARCHAR2, p2 IN VARCHAR2) 
RETURN VARCHAR2 
IS 
    cache_hit NUMBER ; 
    res VARCHAR2(200) ; 
BEGIN 
    SELECT COUNT(*) INTO cache_hit FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ; 

    IF(cache_hit = 1) 
    THEN 
     SELECT MYCACHE.result INTO res FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ; 

     RETURN res ; 
    END IF ; 

    -- complex operations 
    res := p1 || p2 ; 


    INSERT INTO MYCACHE(param1, param2, result) VALUES(p1, p2, res) ; 

    RETURN res ; 
END ; 

次のようになります。

ORA-14551: cannot perform a DML operation inside a query 

手順でDMLの一部をラップしようとしている:私はエラーを得た

SELECT myfct('ABC', 'DEF') FROM DUAL ; 

を関数内でこのプロシージャを呼び出すと助けにならない

私は仕事アラウンドPRAGMA AUTONOMOUS_TRANSACTIONとを発見し、COMMIT:

CREATE OR REPLACE FUNCTION myfct(p1 IN VARCHAR2, p2 IN VARCHAR2) 
RETURN VARCHAR2 
IS 
    PRAGMA AUTONOMOUS_TRANSACTION; 
    cache_hit NUMBER ; 
    res VARCHAR2(200) ; 
BEGIN 
    SELECT COUNT(*) INTO cache_hit FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ; 

    IF(cache_hit = 1) 
    THEN 
     SELECT MYCACHE.result INTO res FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ; 

     RETURN res ; 
    END IF ; 

    -- complex operations 
    res := p1 || p2 ; 


    INSERT INTO MYCACHE(param1, param2, result) VALUES(p1, p2, res) ; 

    COMMIT ; 
    RETURN res ; 
END ; 

しかし、それは本当に良いアイデアであるのだろうか。この回避策に言及した人は、理由を正確に言わずに、危険である可能性があると言いました。

私の関数はPRAGMA AUTONOMOUS_TRANSACTIONの良い使い方の例ですか、あるいは私が欲しいことをするためのより安全な方法がありますか?

+0

PL/SQLで関数を使用してselectを使用する場合は、グローバル・コレクションに結果を保存してから、表にすべての値を挿入する方がよい場合があります。 – SkyWalker

+0

私はそれについて考えましたが、すべての可能な組み合わせでは、格納する行数は数百万になります。定期的に〜10000個の組み合わせを使用する予定です。キャッシュテーブルを持つこのハイブリッドソリューションでは、あらゆる組み合わせに対応することができますが、最も関連性の高いものだけを格納できます。 –

+0

結果を最新の状態に保つことは可能ですか?複合選択の基礎となるデータが変更された場合はどうなりますか?おそらく、あなたは 'マテリアライズドビュー 'であなたのパフォーマンスの問題を解決できますか? –

答えて

3

SQLコンテキストからはどのようなPL/SQLファンクションをコールできるかには制限があります。 SQLコンテキスト内であなたのPL/SQL関数を呼び出すことはありませんが、代わりにPL/SQLコンテキストとすべてに良いことがあります:

declare 
    v_foo constant varchar2(32767) := myfct('foo', 'bar'); 
begin 
    dbmsn_output.put_line(v_foo); 
end; 

しかしあなた自身のキャッシュを実装する前に、OracleのネイティブPL/SQL Function Result Cache -featureを考慮してください。

PL/SQLファンクションの結果キャッシュ・メカニズムは、PL/SQLファンクションの結果をアプリケーションを実行するすべてのセッションで使用可能な共有グローバル領域(SGA)にキャッシュする言語サポートおよびシステム管理方法を提供します。キャッシュメカニズムは効率的で使いやすく、独自のキャッシュとキャッシュ管理ポリシーを設計して開発する負担を軽減します。

結果キャッシュ機能が呼び出されると、システムはキャッシュをチェックします。キャッシュに、同じパラメータ値を持つ関数の前回の呼び出し結果が含まれている場合、システムはキャッシュされた結果を呼び出し元に返し、関数本体を再実行しません。キャッシュに結果が含まれていない場合、システムは関数本体を実行し、呼び出し側に制御を戻す前に結果(これらのパラメーター値用)をキャッシュに追加します。

0

慣例と優れたソフトウェア設計によって、関数はデータベースに変更を加えてはならず、値を返すだけです。代わりにプロシージャを使用してください。これは、PLSQLとCのような単なる関数の両方が存在する理由です。これは主に多くの人が文体的に考えるものです。しかし、私はあなたの用途を分けておくことを強くお勧めします。