Oracle DBMSで多くの人が知っているように、バージョン11g以降、データブロックのバッファーキャッシュと同様に、このために特別に割り当てられたキャッシュに、特定のパラメーターセットの関数を実行した結果を保存するテクノロジーが登場しました。
この記事では、このテクノロジーの「副作用」を使用するオプションを検討します。
result_cacheの適用の本質は簡単です:result_cacheタグでマークされた関数に初めてアクセスした場合(例:v:= foo( 'X'))、この関数が 'X'パラメーターに対して返す結果はキャッシュされます(記憶されます) foo( 'X')に再度アクセスしようとすると、キャッシュから結果が得られます。
これは常にそうですか? そうでもない。 新しい結果のためのスペースが不足しているため、結果をキャッシュからプッシュできます。 コンパイル時にRELISE_ONタグを持つfoo関数と関連付けられたオブジェクトに対してDML操作が呼び出された場合(例:function foo(dept_id number)return number result_cache relies_on(employees)); 関数の再コンパイルにつながるDDL操作呼び出しが発生した場合。 最後に、dbms_result_cache.invalidate関数の呼び出しが発生した場合、結果をキャッシュからプッシュできます。これは、特定の関数のキャッシュを明示的に、または結果キャッシュを管理する他の操作によってクリアする必要があることを示します。
しかし、一般的なケースでは、関数の定数呼び出しでは、必要な関数/パラメーター/値のセットがキャッシュ内で「ホット」になり、これにより不必要な呼び出しが行われないという事実に依存できます。
このテクノロジーの「副作用」は、関数を呼び出すときに、そのコードをほとんど使用しないことです。 次に、これを使用する方法の例を示します。
常にデータが入力されているバッファテーブルがあるとします。 そして、着信データを処理してテーブルをクリアする特定のプロセスがありますが、データは一定の速度で到着するのではなく、高強度の期間とは反対に、新しいデータが不足する期間があります。
一般に、Oracle AQの各レコードの処理のためにリクエストを作成し、これらのリクエストをOracle Schedulerプロセスで処理できます。 スケジューラがアイドル状態になった瞬間、プロセスは終了し、イベントに従って、キュー内のエントリの外観が再び上昇します。 ただし、これは、ベースとCPUおよびIOの負荷と応答時間操作の両方の観点から、タスクを実装する最も効果的な方法ではありません。
もう1つのオプションは、JOBプロセスを常に保持することです。これにより、レコードの外観をテーブルでスキャンし、レコードが表示されたときに有用な作業を行います。サイクルも最も効果的なソリューションではありません。 ここでは、result_cache関数の「プロパティ」を使用できます。
つまり 実行中のタスクの存在を確認し、存在しない場合は開始する特定の関数を作成します。 この関数をresult_cacheとしてマークします。 テーブルを処理するタスクでは、長いダウンタイムの場合にタスクの完了を入力し、最後に(例外の場合でも)、タスクを開始する関数のresult_cacheをリセットします。 最後に、ステートメントレベルのDML操作が(たとえば、レコードが挿入されたときに)実行されたときに起動するトリガーをテーブルにハングアップします。
現在、作業タスクがない場合、テーブルにエントリを挿入すると、タスクが開始されます。タスクがある場合は、キャッシュ内の「フラグ」をチェックします。これは非常に迅速な操作です。 処理プロセスが完了すると、機能ごとにキャッシュがクリアされ、次にトリガーが起動されると、プロセッサプロセスが再び立ち上がります。
以下は、このメソッドを実装するコードですscript.sqlset echo off set verify off set linesize 192 set trim on set trims on spool script.log DROP TABLE EVT_TBL PURGE; DROP TABLE EVT_LOG PURGE; DROP SEQUENCE EVT_SEQ; DROP FUNCTION EVT_CHECK_JOB; DROP PROCEDURE EVT_CREATE_RECORD; DROP PROCEDURE EVT_PRECESS_JOB;
script.log . . . . . . . . . . PL/SQL . . . . NV ---------- -------------------------------------------------- 1 ID: 1 2 ID: 2 3 ID: 3 4 ID: 4 5 ID: 5 6 ID: 6 7 ID: 7 8 ID: 8 9 ID: 9 9 . PL/SQL . NVD ---------- -------------------------------------------------- -------- -30 EXIT JOB: "EVT_PRECESS_JOB;" 15:06:45 -29 SLEEP(5): "EVT_PRECESS_JOB;" 15:06:40 -28 SLEEP(4): "EVT_PRECESS_JOB;" 15:06:36 -27 SLEEP(3): "EVT_PRECESS_JOB;" 15:06:33 -26 SLEEP(2): "EVT_PRECESS_JOB;" 15:06:31 23 ID: 23 15:06:30 -25 START JOB: "EVT_PRECESS_JOB;" 15:06:27 -24 EXECUTE: "EVT_CHECK_JOB;" 15:06:27 -22 EXIT JOB: "EVT_PRECESS_JOB;" 15:06:15 -21 SLEEP(5): "EVT_PRECESS_JOB;" 15:06:10 -20 SLEEP(4): "EVT_PRECESS_JOB;" 15:06:06 NVD ---------- -------------------------------------------------- -------- -19 SLEEP(3): "EVT_PRECESS_JOB;" 15:06:03 -18 SLEEP(2): "EVT_PRECESS_JOB;" 15:06:01 17 ID: 17 15:06:00 16 ID: 16 15:05:59 -15 SLEEP(4): "EVT_PRECESS_JOB;" 15:05:55 -14 SLEEP(3): "EVT_PRECESS_JOB;" 15:05:52 -13 SLEEP(2): "EVT_PRECESS_JOB;" 15:05:50 10 ID: 10 15:05:49 9 ID: 9 15:05:48 8 ID: 8 15:05:47 7 ID: 7 15:05:46 NVD ---------- -------------------------------------------------- -------- 6 ID: 6 15:05:45 5 ID: 5 15:05:44 4 ID: 4 15:05:43 3 ID: 3 15:05:42 2 ID: 2 15:05:41 1 ID: 1 15:05:40 -12 START JOB: "EVT_PRECESS_JOB;" 15:05:37 -11 EXECUTE: "EVT_CHECK_JOB;" 15:05:36 30 .
PS>このスクリプトは単なる魚であることに留意してください。 適切に操作するには、少なくともDBMS_LOCKを介して、処理プロセスの完了時点(つまり、キャッシュリセットの時点)でロックを追加する必要があります。
PPS>この例では、Oracle RACでのresult_cacheの操作の詳細は考慮していません。つまり、各インスタンスには結果の独自のキャッシュがあります。 関数は各インスタンスで少なくとも1回機能します。 インスタンスのいずれかのキャッシュをフラッシュすると、データベース全体がフラッシュされます。
PPPS>これは単なる例です。 特定の問題を解決するためのアクションの推奨ではなく、2つの状態の有限状態マシンの簡単な実装。