PL/SQLファンクション結果キャッシュ

PL/SQLファンクションにRESULT_CACHEオプションを指定すると、その結果がキャッシュされるようになります。これにより、セッションは、キャッシュされた結果を再使用できるようになります(結果が利用可能な場合)。

Oracle Databaseでは、結果がキャッシュされるファンクションの実行中に問合せが行われるすべてのデータ・ソース(表およびビュー)が自動的に検出されます。これらのデータ・ソースのいずれかに対する変更がコミットされると、キャッシュされた結果は、すべてのインスタンスに渡って無効になります。結果キャッシュの対象として最良のファンクションは、頻繁に起動され、ほとんどまたはまったく変更されない情報に依存するファンクションです。

結果オブジェクトは、問合せまたは結果がキャッシュされるファンクションの実行結果です。一時オブジェクトは、RESULT_CACHE_MAX_SIZERESULT_CACHE_MAX_RESULTパラメータの乗算で設定された制限を超える問合せまたは結果がキャッシュされるファンクションの実行結果です。一時オブジェクトは、SYSユーザーに対して定義された一時表領域に格納される一時セグメントです。

結果オブジェクトと一時オブジェクトを一緒に表示するには、一時オブジェクトにTempタイプを使用し、結果オブジェクトにResultタイプを使用してV$RESULT_CACHE_OBJECTSを結合します。

SELECT rc1.NAME, rc2.STATUS, rc3.STATUS, rc2.BLOCK_COUNT
FROM V$RESULT_CACHE_OBJECTS rc1, V$RESULT_CACHE_OBJECTS rc2
WHERE rc1.TYPE = 'Result'
AND rc2.TYPE = 'Temp'
AND rc1.CACHE_KEY = rc2.CACHE_KEY;

RESULT_CACHE_MAX_TEMP_SIZEパラメータは、結果キャッシュがPDBで消費できる一時表領域の最大量を設定します。

結果キャッシュの使用量は、アプリケーション・ワークロードの変更に基づいて最適なパフォーマンスを得るために最適化されます。

キャッシュされた結果をリモート・インスタンスからフェッチする前に、データベースはヒューリスティックを使用して、ローカル・インスタンスで結果を再計算するほうが効率的かどうかを判断します。

Oracle Databaseは、最近使用された結果がキャッシュされるファンクションを追跡します。この履歴を使用することで、データベースは最近の履歴にx回出現する、結果がキャッシュされるファンクションと引数のペアのみをキャッシュします。このxは、初期化パラメータRESULT_CACHE_EXECUTION_THRESHOLDで設定します。デフォルト値が2の場合、結果は2番目の実行でキャッシュされ、3番目の実行で再利用されます。

次の問合せを実行して、結果キャッシュの状態を評価できます。キャッシュされたファンクションの再利用率の分布が表示されます。これらの結果の大部分のスキャン数が0であることに気付いた場合は、RESULT_CACHE_EXECUTION_THRESHOLDの値を1または2増やすことを検討してください。

SELECT SCAN_COUNT, COUNT(CACHE_KEY)
FROM V$RESULT_CACHE_OBJECTS
WHERE NAMESPACE = 'PLSQL'
GROUP BY SCAN_COUNT;

ここでのトピック

ファンクションの結果キャッシュの有効化

ファンクションの結果がキャッシュされるようにするには、ファンクションの宣言と定義にRESULT_CACHE句を含めます。構文の詳細は、「ファンクションの宣言および定義」を参照してください。

ノート:

データベース・サーバーの結果キャッシュの構成と管理の詳細は、『Oracle Databaseリファレンス』および『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

例9-39では、パッケージdepartment_pkgが、結果がキャッシュされるファンクションget_dept_infoを宣言し、定義しています(このファンクションによって、指定した部門に関する情報のレコードが戻されます)。このファンクションは、データベース表のDEPARTMENTSおよびEMPLOYEESに依存します。

ファンクションget_dept_infoは、他のファンクションを起動する場合と同様に起動します。たとえば、次の起動では、部門番号10に関する情報のレコードが戻されます。

department_pkg.get_dept_info(10);

次の起動では、部門番号10の名前のみが戻されます。

department_pkg.get_dept_info(10).dept_name;

get_dept_info(10)の結果が結果キャッシュに含まれている場合、結果はこのキャッシュから戻されますが、そうでない場合は、結果は計算されてキャッシュに追加されます。get_dept_infoDEPARTMENTS表およびEMPLOYEES表に依存するため、DEPARTMENTSまたはEMPLOYEESへの変更がコミットされると、get_dept_infoのキャッシュされた結果はすべて無効になり、DEPARTMENTSまたはEMPLOYEESが変更される可能性のあるすべての場所で、キャッシュ無効化ロジックをプログラミングする必要がなくなります。

例9-39 結果がキャッシュされるファンクションの宣言および定義

CREATE OR REPLACE PACKAGE department_pkg AUTHID DEFINER IS
 
  TYPE dept_info_record IS RECORD (
    dept_name  departments.department_name%TYPE,
    mgr_name   employees.last_name%TYPE,
    dept_size  PLS_INTEGER
  );
 
  -- Function declaration
 
  FUNCTION get_dept_info (dept_id NUMBER)
    RETURN dept_info_record
    RESULT_CACHE;
 
END department_pkg;
/
CREATE OR REPLACE PACKAGE BODY department_pkg IS
  -- Function definition
  FUNCTION get_dept_info (dept_id NUMBER)
    RETURN dept_info_record
    RESULT_CACHE
  IS
    rec  dept_info_record;
  BEGIN
    SELECT department_name INTO rec.dept_name
    FROM departments
    WHERE department_id = dept_id;
 
    SELECT e.last_name INTO rec.mgr_name
    FROM departments d, employees e
    WHERE d.department_id = dept_id
    AND d.manager_id = e.employee_id;
 
    SELECT COUNT(*) INTO rec.dept_size
    FROM EMPLOYEES
    WHERE department_id = dept_id;
 
    RETURN rec;
  END get_dept_info;
END department_pkg;
/

結果がキャッシュされるファンクションを使用するアプリケーションの開発

結果がキャッシュされるファンクションを使用するアプリケーションを開発する場合、指定したパラメータ値のセットに対してそのファンクションの本体が実行される回数については何も想定しないでください。

結果がキャッシュされるファンクションの本体が実行される状況をいくつか次に示します。

  • このデータベース・インスタンスでのセッションが、これらのパラメータ値を使用してファンクションを初めて起動し、実行されたとき

    ノート:

    RESULT_CACHE_EXECUTION_THRESHOLDは、ファンクションと特定の引数セットがキャッシュされるまでに表示する必要がある回数を指定します。そのパラメータのデフォルト値は2で、システム・レベルで構成できます。
  • これらのパラメータ値のキャッシュされた結果が無効である場合

    ファンクションが依存するいずれかのデータソースに対する変更がコミットされると、キャッシュされている結果が無効になります

  • これらのパラメータ値のキャッシュされた結果がエージ・アウトされた場合

    システムでメモリーが必要な場合は、PL/SQLファンクション履歴追跡に基づいて、最も古いキャッシュ値またはほとんど使用されないキャッシュ値が破棄される可能性があります。

  • DBMS_RESULT_CACHEブロック・リスト・プロシージャを起動して、一部の結果キャッシュ関連オブジェクトがローカル・インスタンスまたはグローバルにキャッシュされないように明示的にブロックする場合
  • DBMS_RESULT_CACHE.FLUSHが実行され、SQL問合せのキャッシュされたすべての結果およびPL/SQLファンクションのキャッシュされたすべての結果がフラッシュされた後
  • ファンクションがキャッシュをバイパスする場合(「結果キャッシュのバイパス」を参照)

結果がキャッシュされるファンクションの要件

結果がキャッシュされるPL/SQLファンクションは、あらゆる入力に対して生成される出力が、RESULT_CACHEのマークが付けられていなかった場合に生成される出力と常に同じになるときに安全です。この安全性は、次に示す条件が満たされている場合にのみ保証されます。

  • ファンクションの実行時に、副作用がないこと。

    副作用の詳細は、「サブプログラムの副作用」を参照してください。

  • ファンクションがアクセスするすべての表が、そのファンクションと同じデータベース内に存在する、通常の非SYS所有の永続的な表であること。

  • ファンクションの結果は、常に、そのファンクションが参照する表の現在のSCNでコミットされた内容とあわせた、入力実績のベクトルによってのみ決定されること。

結果がキャッシュされるファンクションでは、次の条件も満たされていることがお薦めされています。

詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

結果がキャッシュされるファンクションの例

結果キャッシュの対象として最良のファンクションは、(最初の例がこれに該当している可能性がありますが)頻繁に起動され、ほとんど変更されない情報に依存するファンクションです。結果キャッシュを行うことによって、再帰ファンクションでの冗長計算が回避されます。

例:

結果がキャッシュされるアプリケーション構成パラメータ

グローバル・レベル、アプリケーション・レベルまたはロール・レベルのいずれのレベルで設定できる構成パラメータを持つアプリケーションについて考えてみます。このアプリケーションは、構成情報を次の表に格納します。

-- Global Configuration Settings
DROP TABLE global_config_params;
CREATE TABLE global_config_params
  (name  VARCHAR2(20), -- parameter NAME
   val   VARCHAR2(20), -- parameter VALUE
   PRIMARY KEY (name)
  );

-- Application-Level Configuration Settings
CREATE TABLE app_level_config_params
  (app_id  VARCHAR2(20), -- application ID
   name    VARCHAR2(20), -- parameter NAME
   val     VARCHAR2(20), -- parameter VALUE
   PRIMARY KEY (app_id, name)
  );

-- Role-Level Configuration Settings
CREATE TABLE role_level_config_params
  (role_id  VARCHAR2(20), -- application (role) ID
   name     VARCHAR2(20),  -- parameter NAME
   val      VARCHAR2(20),  -- parameter VALUE
   PRIMARY KEY (role_id, name)
  );

各構成パラメータで、ロール・レベルの設定はアプリケーション・レベルの設定をオーバーライドし、アプリケーション・レベルの設定はグローバル設定をオーバーライドします。パラメータに適用される設定を決定するために、このアプリケーションはPL/SQLファンクションget_valueを定義します。パラメータ名、アプリケーションIDおよびロールIDを指定すると、get_valueはそのパラメータに適用される設定を戻します。

ファンクションget_valueが頻繁に起動され、構成情報はほとんど変更されない場合、このファンクションは結果キャッシュの対象として最良のファンクションとなります。

例9-40に、get_valueに指定可能な定義を示します。あるパラメータ値のセットに対して、グローバル設定によってget_valueの結果が決まるとします。get_valueの実行中に、データベースでは3つの表role_level_config_paramsapp_level_config_paramsおよびglobal_config_paramsの問合せが検出されます。これらの3つの表のいずれに対する変更がコミットされても、このパラメータ値のセットについてキャッシュされた結果は無効となり、再計算する必要があります。

次に、2番目のパラメータ値セットに対して、ロール・レベルの設定によってget_valueの結果が決定されるとします。get_valueの実行中に、データベースでは表role_level_config_paramsの問合せのみが検出されます。role_level_config_paramsに対する変更がコミットされると、2番目のパラメータ値セットについてキャッシュされた結果は無効となりますが、app_level_config_paramsまたはglobal_config_paramsに対する変更がコミットされてもキャッシュされた結果には影響がありません。

例9-40 構成パラメータの設定を返す、結果がキャッシュされるファンクション

CREATE OR REPLACE FUNCTION get_value
  (p_param VARCHAR2,
   p_app_id  NUMBER,
   p_role_id NUMBER
  )
  RETURN VARCHAR2
  RESULT_CACHE
  AUTHID DEFINER
IS
  answer VARCHAR2(20);
BEGIN
  -- Is parameter set at role level?
  BEGIN
    SELECT val INTO answer
      FROM role_level_config_params
        WHERE role_id = p_role_id
          AND name = p_param;
    RETURN answer;  -- Found
    EXCEPTION
      WHEN no_data_found THEN
        NULL;  -- Fall through to following code
  END;
  -- Is parameter set at application level?
  BEGIN
    SELECT val INTO answer
      FROM app_level_config_params
        WHERE app_id = p_app_id
          AND name = p_param;
    RETURN answer;  -- Found
    EXCEPTION
      WHEN no_data_found THEN
        NULL;  -- Fall through to following code
  END;
  -- Is parameter set at global level?
    SELECT val INTO answer
     FROM global_config_params
      WHERE name = p_param;
    RETURN answer;
END;
/

結果がキャッシュされる再帰ファンクション

フィボナッチ数列の数学的定義を模倣した、フィボナッチ数列のn番目の項を検索するための再帰ファンクションは、多くの冗長計算を実行する可能性があります。たとえば、fibonacci(7)を評価するために、このファンクションはfibonacci(6)およびfibonacci(5)を計算する必要があります。fibonacci(6)を計算するために、このファンクションはfibonacci(5)およびfibonacci(4)を計算する必要があります。このため、fibonacci(5)などのいくつかの項は、重複して計算されます。結果キャッシュを行うことによって、これらの冗長計算が回避されます。

ノート:

キャッシュされる再帰的起動の数は、最大で128です。

CREATE OR REPLACE FUNCTION fibonacci (n NUMBER)
  RETURN NUMBER
  RESULT_CACHE
  AUTHID DEFINER
IS
BEGIN
  IF (n =0) OR (n =1) THEN
    RETURN 1;
  ELSE
    RETURN fibonacci(n - 1) + fibonacci(n - 2);
  END IF;
END;
/

結果がキャッシュされるファンクションの高度なトピック

ここでのトピック

キャッシュ・ヒットの規則

結果がキャッシュされるファンクションが異なるパラメータ値で起動されるたびに、それらのパラメータおよびそれぞれの結果がキャッシュに格納されます。それ以降、同じファンクションが同じパラメータ値で起動されると(つまり、キャッシュ・ヒットがある場合)、結果は再計算されるのではなく、キャッシュから取り出されます。

キャッシュ・ヒット用のパラメータ比較の規則は、次に示すように、PL/SQLの「等号」(=)演算子の規則とは異なります。

カテゴリ キャッシュ・ヒットの規則 「等号」演算子の規則

NULLの比較

NULLNULLに一致します

NULL = NULLの評価結果はNULLです。

NULLでないスカラーの比較

NULLでないスカラーは、それぞれの値が同一である場合にのみ同じとなります(つまり、指定されたプラットフォームでそれぞれの値が同一のビット・パターンを持っている場合にのみ同じとなります)。たとえば、CHAR'AA''AA 'は異なります。(この規則の方が、「等号」演算子の規則より厳密です。)

NULLでないスカラーは、指定されたプラットフォームでそれぞれの値が同一のビット・パターンを持っていない場合でも、等しくなる可能性があります。たとえば、CHAR'AA''AA'は等しくなります。

結果キャッシュのバイパス

場合によって、キャッシュはバイパスされます。キャッシュがバイパスされる場合を次に示します。

  • ファンクションが結果をキャッシュから取り出すのではなく、計算する場合。

  • ファンクションが計算する結果がキャッシュに追加されない場合。

キャッシュがバイパスされる場合の例を次にいくつか示します。

  • すべてのセッションでキャッシュを使用できない場合。

    たとえば、データベース管理者がアプリケーションへのパッチの適用中に、結果キャッシュを使用できない状態にした場合などです(「結果がキャッシュされるファンクションが依存するPL/SQLユニットへのホット・パッチの適用」を参照)。

  • 結果がキャッシュされるファンクションが依存する表またはビューに対して、セッションがDML文を実行している場合。

    このセッションは、そのDML文が完了するまで(コミットまたはロールバックされるまで)そのファンクションの結果キャッシュをバイパスします。その文がロールバックされると、このセッションは、そのファンクションのキャッシュの使用を再開します。

    キャッシュをバイパスすると、次のことが保証されます。

    • 各セッションのユーザーは、コミットされていないユーザー独自の変更を参照できます。

    • PL/SQLファンクションの結果キャッシュには、すべてのセッションで参照可能なコミットされた変更のみが含まれます。このため、あるセッションでコミットされていない変更は、他のセッションでは参照できません。

結果がキャッシュされるファンクションによるセッション固有の設定の処理

セッションによって異なる可能性がある設定(NLS_DATE_FORMATTIME ZONEなど)にファンクションが依存している場合は、様々な設定を処理できるようにそのファンクションを変更できる場合にのみ、そのファンクションの結果がキャッシュされるようにします。

例8–39のファンクションget_hire_dateは、TO_CHARファンクションを使用してDATE項目をVARCHAR項目に変換しています。ファンクションget_hire_dateに書式マスクが指定されていないため、書式マスクは、デフォルトでNLS_DATE_FORMATに指定されている書式マスクになります。get_hire_dateを起動するセッションのNLS_DATE_FORMAT設定が異なっている場合、キャッシュされた結果の書式も異なる可能性があります。あるセッションで計算されてキャッシュされた結果がエージ・アウトされ、別のセッションで再計算された場合、同じパラメータ値に対する場合でも、書式が異なる可能性があります。キャッシュされた結果がセッションで取得され、結果の書式がセッションの書式とは異なる場合、その結果は不適切である可能性があります。

この問題の解決方法をいくつか次に示します。

  • get_hire_dateの戻り型をDATEに変更し、各セッションがTO_CHARファンクションを起動するようにします。

  • ある共通の書式がすべてのセッションで受入れ可能である場合は、書式マスクを指定して、NLS_DATE_FORMATへの依存性を削除します。たとえば:

    TO_CHAR(date_hired, 'mm/dd/yy');
    
  • 書式マスクのパラメータをget_hire_dateに追加します。たとえば:

    CREATE OR REPLACE FUNCTION get_hire_date (emp_id NUMBER, fmt VARCHAR)
      RETURN VARCHAR
      RESULT_CACHE
      AUTHID DEFINER
    IS
      date_hired DATE;
    BEGIN
      SELECT hire_date INTO date_hired
        FROM HR.EMPLOYEES
          WHERE EMPLOYEE_ID = emp_id;
      RETURN TO_CHAR(date_hired, fmt);
    END;
    /

例9-41 結果がキャッシュされるファンクションによるセッション固有の設定の処理

CREATE OR REPLACE FUNCTION get_hire_date (emp_id NUMBER)
  RETURN VARCHAR
  RESULT_CACHE
  AUTHID DEFINER
IS
  date_hired DATE;
BEGIN
  SELECT hire_date INTO date_hired
    FROM HR.EMPLOYEES
      WHERE EMPLOYEE_ID = emp_id;
  RETURN TO_CHAR(date_hired);
END;
/

結果がキャッシュされるファンクションによるセッション固有のアプリケーション・コンテキストの処理

アプリケーション・コンテキストは、グローバルまたはセッション固有のいずれかで、属性とそれらの値の集合のことです。PL/SQLファンクションは、次の1つ以上の項目を実行する場合、セッション固有のアプリケーション・コンテキストに依存します。

  • 指定したコンテキストで指定した属性の値を戻すSQLファンクションSYS_CONTEXTの直接起動

  • ファイングレイン・セキュリティのための仮想プライベート・データベース(VPD)・メカニズムを使用したSYS_CONTEXTの間接起動

    (VPDの詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください)

PL/SQLファンクションの結果キャッシュ機能は、セッション固有のアプリケーション・コンテキストへの依存性を自動的には処理しません。セッション固有のアプリケーション・コンテキストに依存しているファンクションの結果をキャッシュする必要がある場合は、アプリケーション・コンテキストをパラメータとしてファンクションに渡す必要があります。このパラメータにはデフォルト値を指定できるため、すべてのユーザーがこのパラメータを指定する必要があるわけではありません。

例9-42では、表config_tabに、次に示す問合せを変換するVPDポリシーがあると想定しています。

SELECT value FROM config_tab WHERE name = param_name;

この問合せへ:

SELECT value FROM config_tab
WHERE name = param_name
AND app_id = SYS_CONTEXT('Config', 'App_ID');

例9-42 結果がキャッシュされるファンクションによるセッション固有のアプリケーション・コンテキストの処理

CREATE OR REPLACE FUNCTION get_param_value (
  param_name VARCHAR,
  appctx     VARCHAR  DEFAULT SYS_CONTEXT('Config', 'App_ID')
) RETURN VARCHAR
  RESULT_CACHE
  AUTHID DEFINER
IS
  rec VARCHAR(2000);
BEGIN
  SELECT val INTO rec
  FROM config_tab
  WHERE name = param_name;
 
  RETURN rec;
END;
/

結果キャッシュの粒度の選択

PL/SQLにはファンクション結果キャッシュが用意されていますが、キャッシュの粒度はユーザーが選択します。粒度の概念を理解するために、Order Entry(OE)サンプル・スキーマ内のProduct_Descriptions表について考えてみます。

NAME                     NULL?      TYPE
----------------------   --------   ---------------
PRODUCT_ID               NOT NULL   NUMBER(6)
LANGUAGE_ID              NOT NULL   VARCHAR2(3)
TRANSLATED_NAME          NOT NULL   NVARCHAR2(50)
TRANSLATED_DESCRIPTION   NOT NULL   NVARCHAR2(2000)

この表には、各製品の名前と説明が複数の言語で記載されています。各行の一意のキーは、PRODUCT_ID,LANGUAGE_IDです。

PRODUCT_IDおよびLANGUAGE_IDを受け取って、関連付けられたTRANSLATED_NAMEを戻すファンクションを定義する必要があるとします。また、変換された名前をキャッシュする必要もあるとします。これらの名前をキャッシュする場合の粒度の選択肢の一部を次に示します。

  • 一度に1つの名前(粒度が細かい)

  • 一度に1つの言語(粒度が粗い)

表9-4 粒度が細かいキャッシュと粗いキャッシュ

粒度 利点

細かい

各ファンクション結果は、1つの論理結果に対応しています。

1回以上必要とされるデータのみを格納します。

各データ項目は、個別にエージ・アウトされます。

バルク・ロードは最適化できません。

粗い

各ファンクション結果には、多数の論理的部分結果が含まれています。

使用されることのないデータを格納する場合もあります。

1つのデータ項目がエージ・アウトされると、全体がエージ・アウトされます。

バルク・ロードを最適化できます。

例9-43および例9-44では、ファンクションproductNamePRODUCT_IDおよびLANGUAGE_IDを取り、関連付けられたTRANSLATED_NAMEを戻しています。productNameの各バージョンは、変換された名前をキャッシュしますが、キャッシュする際の粒度はそれぞれ異なっています。

例9-43では、get_product_name_1は結果がキャッシュされるファンクションです。get_product_name_1は、別のPRODUCT_IDおよびLANGUAGE_IDで起動されると、常に関連付けられたTRANSLATED_NAMEをキャッシュします。get_product_name_1が起動されるたびに、最大1つのTRANSLATED_NAMEがキャッシュに追加されます。

例9-44では、get_product_name_2は、結果がキャッシュされるファンクションall_product_namesを定義します。get_product_name_2が別のLANGUAGE_IDall_product_namesを起動すると、常にall_product_namesはそのLANGUAGE_IDに関連付けられたすべてのTRANSLATED_NAMEをキャッシュします。all_product_namesが起動されるたびに、最大1つのLANGUAGE_IDのすべてのTRANSLATED_NAMEがキャッシュに追加されます。

例9-43 一度に1つの名前のキャッシュ(粒度が細かい)

CREATE OR REPLACE FUNCTION get_product_name_1 (
  prod_id NUMBER,
  lang_id VARCHAR2
)
  RETURN NVARCHAR2
  RESULT_CACHE
  AUTHID DEFINER
IS
  result_ VARCHAR2(50);
BEGIN
  SELECT translated_name INTO result_
  FROM OE.Product_Descriptions
  WHERE PRODUCT_ID = prod_id
  AND LANGUAGE_ID = lang_id;
  RETURN result_;
END;
/

例9-44 一度に1つの言語の変換された名前のキャッシュ(粒度が粗い)

CREATE OR REPLACE FUNCTION get_product_name_2 (
  prod_id NUMBER,
  lang_id VARCHAR2
)
  RETURN NVARCHAR2
  AUTHID DEFINER
IS
  TYPE product_names IS TABLE OF NVARCHAR2(50) INDEX BY PLS_INTEGER;
 
  FUNCTION all_product_names (lang_id VARCHAR2)
    RETURN product_names
    RESULT_CACHE
  IS
    all_names product_names;
  BEGIN
    FOR c IN (SELECT * FROM OE.Product_Descriptions
              WHERE LANGUAGE_ID = lang_id) LOOP
      all_names(c.PRODUCT_ID) := c.TRANSLATED_NAME;
    END LOOP;
    RETURN all_names;
  END;
BEGIN
  RETURN all_product_names(lang_id)(prod_id);
END;
/

Oracle RAC環境での結果キャッシュ

キャッシュされた結果はシステム・グローバル領域(SGA)に格納されます。Oracle RAC環境では、各データベース・インスタンスによって、そのインスタンス独自のローカルなファンクション結果キャッシュが管理されます。ただし、ローカルな結果キャッシュの内容は、他のOracle RACインスタンスに付随するセッションからアクセスできます。必要な結果がローカル・インスタンスの結果キャッシュから欠落している場合、ローカルで計算するのではなく、他のインスタンスのローカル・キャッシュから結果が取り出される場合があります。インスタンスのアクセス・パターンおよびワークロードによって、そのインスタンスのローカル・キャッシュに格納される結果セットが決まります。このため、インスタンスが異なると、そのローカル・キャッシュに格納される結果セットも異なります。

キャッシュされた結果をリモート・インスタンスからフェッチする前に、データベースはヒューリスティックを使用して、ローカル・インスタンスで結果を再計算するほうが効率的かどうかを判断します。この機能の使用を監視するには、V$RESULT_CACHE_OBJECTSビューとV$RESULT_CACHE_STATISTICSビューを問い合せます。オブジェクトが別のインスタンスの結果キャッシュからフェッチされた場合、V$RESULT_CACHE_OBJECTSGLOBAL列の値はYesになります。値'No'は、結果がリモートで使用できなかったか、システムがリモートでフェッチするより効率的であると判断したために、結果がローカルで再計算されたことを意味します。V$RESULT_CACHE_STATISTICSビューの統計'Global Prune Count'は、リモート・インスタンスからフェッチしないと決定された回数を示します。'Global Prune By Self Count'は、インスタンスがローカル結果の提供を要求し、リクエスト元のインスタンスが結果をローカルに計算するほうがより効率的であると判断した回数を示します。最後に、'Global Load Rate'は、他のインスタンスの結果キャッシュから結果をフェッチする計算速度(10ミリ秒当たりのバイト数)を示します。これらの統計はすべて、RAC環境のグローバル結果キャッシュにのみ適用されます。

各データベース・インスタンスには、そのインスタンス独自のキャッシュされた結果セットが含まれている可能性がありますが、無効な結果を処理するメカニズムはOracle RAC環境全体にわたります。たとえば、データベース表内のデータから計算される品目の価格の結果キャッシュについて考えてみます。ある品目の価格に影響を与える方法でこれらのデータベース表のいずれかが更新された場合、キャッシュされたその品目の価格はOracle RAC環境内のすべてのデータベース・インスタンスで無効になります。

関連項目:

Oracle RACデータベースでの RESULT_CACHE_MAX_SIZEパラメータおよびその他の初期化パラメータの設定の詳細は、Oracle Real Application Clusters管理およびデプロイメント・ガイドを参照してください

結果キャッシュの管理

PL/SQLファンクション結果キャッシュは、その管理および管理性インフラストラクチャを結果キャッシュと共有します。

DBMS_RESULT_CACHEサブプログラムを使用して、SQL結果キャッシュおよびPL/SQLファンクション結果キャッシュによって使用される共有プール領域部分を管理できます。DBMS_RESULT_CACHE.BLACKLIST_ADDプロシージャを使用すると、問合せまたはPL/SQLファンクションをブロックリストに追加して、結果のキャッシュを停止できます。バインド変数または引数のどちらを使用しても、オブジェクトは生成されません。結果キャッシュの行ソースは実行計画に引き続き表示されますが、実行時にはno-opになります。ファンクションに対して何万ものキャッシュ結果の一意の引数が実行されるケースを検索して診断すると、結果キャッシュの問題を解決できます。ワークロードによっては、これらのキャッシュされた結果を管理するオーバーヘッドによって、結果をキャッシュする利点が相殺される場合があります。パフォーマンス・ビューを使用すると、この特別なケースを把握できます。

問合せを実行して、問題のある問合せまたはファンクションを識別できます。cache_idは、SQLカーソルまたはPL/SQLファンクションの結果キャッシュ識別子です。この問合せは、各キャッシュIDに対して行われた一意の結果キャッシュ・オブジェクトの数をカウントします。一意のバインド変数または引数を持つ問合せまたはファンクションを実行するたびに、一意のオブジェクトが作成されます。

SELECT cache_id, COUNT(cache_key) AS uniq_args
FROM GV$RESULT_CACHE_OBJECTS
WHERE type = 'Result'
GROUP BY cache_id
ORDER BY uniq_args DESC;

依存オブジェクトがワークロードによって頻繁に更新される場合、結果キャッシュを使用することによるパフォーマンス上の利点に悪影響を与える可能性があります。たとえば、大規模なトランザクションがコミットされ、すでにキャッシュされている結果に影響を与える場合、間違った結果を防ぐために、これらのキャッシュされた結果を無効にするメッセージが送信されます。このボトルネックが発生している最初のヒントとして、GV$CHANNEL_WAITSビューのCHANNEL = 'Result Cache: Channel'で高待機が観察されます。問合せを実行してculpritをチェックし、ブロックリストへのオブジェクトの追加などの適切なアクションを実行できます。無効化の数が非常に多いオブジェクトは、この問合せを使用して診断できます。

SELECT object_no, SUM(invalidations) AS num_invals
FROM GV$RESULT_CACHE_OBJECTS
WHERE type = 'Dependency'
GROUP BY object_no
ORDER BY num_invals DESC;

関連項目:

動的パフォーマンスのビューには、サーバーとクライアントの結果キャッシュを監視するための情報が示されます。

関連項目:

データベース管理者は、結果キャッシュの初期化パラメータを指定して、サーバー結果キャッシュを管理します。

関連項目:

  • サーバー結果キャッシュのインフラストラクチャの詳細は、Oracle Database概要を参照してください

結果がキャッシュされるファンクションが依存するPL/SQLユニットへのホット・パッチの適用

結果がキャッシュされるファンクションが依存するPL/SQLユニットに(直接または間接的に)ホット・パッチを適用する際、結果がキャッシュされるファンクションに関連付けられているキャッシュされた結果がすべての場合に自動的にフラッシュされるとはかぎりません。

たとえば、結果がキャッシュされるファンクションP1.foo()がパッケージ・サブプログラムP2.bar()に依存しているとします。パッケージP2の本体の新しいバージョンがロードされた場合、P1.foo()に関連付けられているキャッシュされた結果は、自動的にはフラッシュされません。

このため、PL/SQLユニットへのホット・パッチの適用には、次の手順を実行することをお薦めします。

ノート:

これらのステップに従うには、DBMS_RESULT_CACHEパッケージに対するEXECUTE権限が必要です。

  1. 結果キャッシュをバイパス・モードに設定し、既存の結果をフラッシュします。
    BEGIN
      DBMS_RESULT_CACHE.Bypass(TRUE);
      DBMS_RESULT_CACHE.Flush;
    END;
    /

    Oracle RAC環境では、各データベース・インスタンスに対してこのステップを実行します。

  2. PL/SQLコードにパッチを適用します。
  3. 結果キャッシュの使用を再開します。
    BEGIN
      DBMS_RESULT_CACHE.Bypass(FALSE);
    END;
    /

    Oracle RAC環境では、各データベース・インスタンスに対してこのステップを実行します。