20 文キャッシュと結果セット・キャッシュ

この章では、Oracle Java Database Connectivity(JDBC)拡張要素である文キャッシュの利点と使用方法について説明します。

ノート:

表の構造がデータベース内で同じ場合にのみ、文キャッシュを使用します。表の構造を変更し、変更前に作成および実行した文を再利用した場合、エラーが発生することがあります。

この章の構成は、次のとおりです。

20.1 文キャッシュについて

文キャッシュにより、繰り返しコールされるループやメソッドなどで何度も使用する実行文がキャッシュされるため、パフォーマンスが向上します。JDBC 3.0以降では、JDBC標準で文キャッシュ・インタフェースが定義されています。

文キャッシュでは、次のことができます。

  • カーソル作成の繰返しによるオーバーヘッドを回避します。

  • 文の解析と作成の繰返しを回避します。

  • クライアント内のデータ構造を再利用します。

この項の内容は次のとおりです。

ノート:

暗黙的文キャッシュの使用を強くお薦めします。Oracle JDBCドライバは暗黙的文キャッシュが有効になっているという前提で設計されています。このため、文キャッシュを使用しないとパフォーマンスに悪影響を及ぼします。

20.1.1 文キャッシュの基本

アプリケーションでは、特定の物理接続に関連付けられている文をキャッシュするために文キャッシュを使用します。このキャッシュはOracleConnectionオブジェクトに関連付けられています。OracleConnectionには、文キャッシュを有効にするメソッドが含まれています。文キャッシュを有効にすると、closeメソッドをコールするときに文オブジェクトがキャッシュされます。

物理接続ごとに独自のキャッシュがあるため、複数の物理接続に対して文キャッシュを有効にすると複数のキャッシュが存在することになります。接続キャッシュで文キャッシュを有効にすると、基礎となる物理接続で有効な文キャッシュが論理接続で利用されます。接続キャッシュによって保持されている論理接続で文キャッシュを有効にしようとすると、例外が発生します。

文キャッシュには、暗黙的文キャッシュと明示的文キャッシュの2つのタイプがあります。文キャッシュの各タイプは、互いに関係なく有効または無効にできます。いずれかを有効にするか、いずれも有効にしないか、または両方とも有効にすることができます。両方のタイプの文キャッシュで、接続ごとに1つのキャッシュが共有されます。

20.1.2 暗黙的文キャッシュ

暗黙的文キャッシュを有効にすると、JDBCでは、プリペアド文またはコール可能文の文オブジェクトのcloseメソッドをコールしたときに、その文が自動的にキャッシュされます。プリペアド文およびコール可能文のキャッシュおよび取出しには、標準の接続オブジェクトおよび文オブジェクト・メソッドを使用します。

暗黙的文キャッシュはSQL文字列をキーとして使用しますが、プレーン文はSQL文字列を使用せずに作成されるため、プレーン文は暗黙的にキャッシュされません。このため、暗黙的文キャッシュは、SQL文字列を使用して作成されるOraclePreparedStatementおよびOracleCallableStatementオブジェクトにのみ適用されます。OracleStatementとともに暗黙的文キャッシュを使用することはできませんOraclePreparedStatementまたはOracleCallableStatementを作成するとき、JDBCドライバはキャッシュを自動的に検索し、一致する文を探します。一致基準は、次のとおりです。

  • 文内のSQL文字列は、キャッシュのSQL文字列と同一である必要があります。

  • 文の種類は、同じにする必要があります。つまり、プリペアド文またはコール可能文にします。

  • 文によって生成される結果セットのスクロール可能な型は、同じにする必要があります。つまり、forward-onlyまたはscrollableにします。

キャッシュ検索中に一致するものが見つかった場合は、キャッシュされた文が戻されます。一致するものが見つからなかった場合は、新しい文が作成されて戻されます。どちらの場合でも、文は、そのカーソルおよび状態とともに、文オブジェクトのcloseメソッドをコールするとキャッシュされます。

キャッシュされたOraclePreparedStatementまたはOracleCallableStatementオブジェクトが取り出されると、状態およびデータ情報は自動的に再初期化されて、デフォルト値にリセットされますが、メタデータは保存されます。最大サイズに準拠するため、最低使用頻度(LRU)アルゴリズムを使用してキャッシュから文が削除されます。

ノート:

JDBCドライバは、メタデータをクリアしません。メタデータはパフォーマンスの理由から保存されますが、セマンティクスへの影響はありません。暗黙的キャッシュによる文は、新たに作成された場合と同様に動作します。

特定の文を暗黙的なキャッシュの対象から外すことができます。

20.1.3 明示的文キャッシュ

明示的文キャッシュによって、プリペアド文およびコール可能文を選択してキャッシュし、取り出すことができます。明示的文キャッシュは、ユーザーが指定する任意のJava Stringであるキーに依存します。

ノート:

プレーン文はキャッシュできません。

明示的文キャッシュは文のデータ、状態およびメタデータを保持するため、メタデータのみを保持する暗黙的文キャッシュに対してパフォーマンス上は有利です。ただし、このタイプのキャッシュを使用する場合は慎重である必要があります。明示的文キャッシュは再利用のために3つの種類の情報をすべて保存するため、前回の文の使用から、どのようなデータと状態が保持されているかわからない場合があります。

暗黙的文キャッシュと明示的文キャッシュは次の点が異なります。

  • 文の取出し

    暗黙的文キャッシュの場合は、文をキャッシュから取り出すための特別な処理は不要です。かわりに、prepareStatementまたはprepareCallをコールするたびに、JDBCでは一致する文についてキャッシュが自動的にチェックされ、見つかった場合はその文が戻されます。しかし、明示的文キャッシュの場合は、専用のOracle WithKeyメソッドを使用して、文オブジェクトをキャッシュし、取り出します。

  • キーの指定

    暗黙的文キャッシュでは、プリペアド文またはコール可能文のSQL文字列がキーとして使用され、ユーザーは特にアクションを実行する必要はありません。これに対し明示的文キャッシュでは、キーとして使用するJava Stringを指定する必要があります。

  • 文の戻り

    暗黙的文キャッシュの実行中に、JDBCドライバでキャッシュ内に一致する文を見つけられない場合は、新しい文が自動的に作成されます。しかし、明示的文キャッシュの実行中にJDBCドライバでキャッシュ内に一致する文を見つけられない場合は、NULL値が戻されます。

表20-1で、暗黙的文キャッシュと明示的文キャッシュで使用されるメソッドの違いを比較します。

表20-1 文キャッシュで使用されるメソッドの比較

キャッシュのタイプ 割当て キャッシュへの挿入 キャッシュからの取出し

暗黙的

prepareStatement prepareCall

close

prepareStatement prepareCall

明示的

createStatement prepareStatement prepareCall

closeWithKey

getStatementWithKey getCallWithKey

20.2 文キャッシュの使用について

この項では、次の項目について説明します。

20.2.1 文キャッシュの有効化および無効化について

OracleConnection APIを使用する場合は、暗黙的および明示的な文キャッシュは、互いに関係なく有効または無効にできます。いずれかを有効にするか、いずれも有効にしないか、または両方とも有効にすることができます。

暗黙的文キャッシュの有効化

暗黙的文キャッシュを有効にする方法は2つあります。最初のメソッドは、プールされていない物理接続上で文キャッシュを有効にします。ここでは、setStatementCacheSize メソッドを使用して、すべての接続に対する文サイズを明示的に指定する必要があります。2番目のメソッドは、プールされている論理接続上で文キャッシュを有効にします。プール内のそれぞれの接続は、MaxStatementsLimitプロパティを設定することで指定できる最大サイズが同一である、独自の文キャッシュを持っています。

メソッド1

次のステップを実行します。

  • 接続でOracleDataSource.setImplicitCachingEnabled(true)メソッドをコールして、OracleDataSourceプロパティimplicitCachingEnabledtrueに設定します。次に例を示します。

    OracleDataSource ods =  new OracleDataSource();
    ...
    ods.setImplicitCachingEnabled(true);
    ...
    
  • 物理接続でOracleConnection.setStatementCacheSizeメソッドをコールします。引数にはキャッシュ内の文の最大数を指定します。たとえば、次のコードでは、キャッシュ・サイズを10の文に指定します。

    ((OracleConnection)conn).setStatementCacheSize(10);
    

メソッド2

次のステップを実行します。

  • OracleDataSourceプロパティのimplicitCachingEnabledおよびconnectionCachingEnabledtrueに設定します。次に例を示します。

    OracleDataSource ods =  new OracleDataSource();
    ...
    ods.setConnectionCachingEnabled( true );
    ods.setImplicitCachingEnabled( true );
    ...
    
  • 接続キャッシュを使用する場合は、接続キャッシュでMaxStatementsLimitプロパティを正の整数に設定します。次に例を示します。

    Properties cacheProps = new Properties();
    ...
    cacheProps.put( "MaxStatementsLimit", "50" );
    

暗黙的キャッシュが有効になっているかどうかを判断するには、getImplicitCachingEnabledをコールします。暗黙的キャッシュが有効な場合はtrueが、それ以外の場合はfalseが戻されます。

ノート:

文キャッシュを有効にすると、暗黙的文キャッシュと明示的文キャッシュの両方が有効になります。

暗黙的文キャッシュの無効化

暗黙的文キャッシュを無効にするには、接続でsetImplicitCachingEnabled(false)をコールするか、またはImplicitCachingEnabledプロパティをfalseに設定します。

明示的文キャッシュの有効化

明示的文キャッシュを有効にするには、最初に文キャッシュ・サイズを設定する必要があります。キャッシュ・サイズを設定するために、物理接続でOracleConnection.setStatementCacheSizeをコールします。引数にはキャッシュ内の文の最大数を指定します。0(ゼロ)を指定すると、キャッシングは行われません。キャッシュ・サイズのチェックには、次のようにgetStatementCacheSizeメソッドを使用します。

System.out.println("Stmt Cache size is " +
   ((OracleConnection)conn).getStatementCacheSize());

次のコードでは、キャッシュ・サイズを10の文に指定します。

((OracleConnection)conn).setStatementCacheSize(10);

接続でsetExplicitCachingEnabled(true)をコールすることにより、明示的文キャッシュを有効にします。

明示的キャッシュが有効になっているかどうかを判断するには、getExplicitCachingEnabledをコールします。明示的キャッシュが有効な場合はtrueが、それ以外の場合はfalseが戻されます。

ノート:

  • 特定の物理接続に対しては、暗黙的キャッシュと明示的キャッシュを別々に有効にします。このため、同じセッション中で暗黙的文キャッシュと明示的文キャッシュの両方を実行できるわけです。

  • 暗黙的文キャッシュと明示的文キャッシュは、同一のキャッシュを共有します。文キャッシュのサイズ設定では、この点を考慮してください。

明示的文キャッシュの無効化

setExplicitCachingEnabled(false)をコールすることにより、明示的文キャッシュを無効にします。キャッシュを無効化またはクローズすると、そのキャッシュは消去されます。次の例では、明示的文キャッシュを無効にします。

((OracleConnection)conn).setExplicitCachingEnabled(false);

20.2.2 キャッシュされた文のクローズについて

文をクローズし、それが確実にキャッシュに戻されないようにするには次の操作を行います。

J2SE 5.0の場合

  • その文のキャッシュを無効にします。

    stmt.setDisableStmtCaching(true);
    
  • 文オブジェクトのcloseメソッドをコールします。

    stmt.close();
    

JSE 6.0の場合

stmt.setPoolable(false);
stmt.close();

キャッシュされた文の物理的なクローズ

暗黙的文キャッシュを有効にすると、文の物理的なクローズを手動で実行できなくなります。文オブジェクト・キャッシュのcloseメソッドは、文をクローズするのではなく、キャッシュします。文は、次の3つの条件の1つで自動で物理的にクローズされます。

  • 関連付けられている接続がクローズされた場合

  • キャッシュがそのサイズ制限に達し、LRUアルゴリズムにより、最低使用頻度の文オブジェクトが優先的に取得される場合

  • 文キャッシュが無効にされている文でcloseメソッドをコールした場合

20.2.3 暗黙的文キャッシュの使用方法について

暗黙的文キャッシュを有効にすると、デフォルトではすべてのプリペアド文およびコール可能文が自動的にキャッシュされます。暗黙的文キャッシュでは、次のステップが実行されます。

  1. 暗黙的文キャッシュを有効にします。

  2. 標準メソッドの1つを使用して文を割り当てます。

  3. キャッシュの対象としない特定の文に対する暗黙的文キャッシュを無効にします。これはオプションのステップです。

  4. closeメソッドを使用して文をキャッシュします。

  5. 暗黙的にキャッシュされた文を取り出すには、適切な標準のprepareメソッドをコールします。

暗黙的キャッシュのための文の割当て

暗黙的文キャッシュに文を割り当てるには、通常prepareStatementまたはprepareCallメソッドを使用します。

次のコードでは、pstmtと呼ばれる新しい文オブジェクトを割り当てます。

PreparedStatement pstmt = conn.prepareStatement
   ("UPDATE emp SET ename = ? WHERE rowid = ?");

特定の文に対する暗黙的文キャッシュの無効化

ある接続の暗黙的文キャッシュを有効にすると、デフォルトでは、その接続のすべてのコール可能文およびプリペアド文が自動的にキャッシュされます。特定のコール可能文またはプリペアド文が暗黙的にキャッシュされないようにするには、文オブジェクトのsetDisableStmtCachingメソッドを使用します。キャッシュ領域を管理するためには、使用頻度の低い文でsetDisableStmtCachingメソッドをコールします。

次のコードでは、pstmtに対する暗黙的文キャッシュを無効にします。

PreparedStatement pstmt = conn.prepareStatement("SELECT 1 from DUAL");
((OraclePreparedStatement)pstmt).setDisableStmtCaching(true);
pstmt.close ();

ノート:

JSE 6を使用している場合は、標準JDBC 4.0メソッドsetPoolableを使用して文キャッシュを無効にします。

PreparedStatement.setPoolable(false);

次のコマンドを使用してStatementオブジェクトがプール可能かどうかを確認します。

Statement.isPoolable();

文の暗黙的なキャッシュ

割り当てられた文をキャッシュするには、文オブジェクトのcloseメソッドをコールします。OraclePreparedStatementまたはOracleCallableStatementオブジェクトでcloseメソッドをコールすると、この文のキャッシュを無効にしていないかぎり、JDBCドライバではこの文がキャッシュ内に自動的に挿入されます。

次のコードでは、pstmt文をキャッシュします。

pstmt.close ();

暗黙的にキャッシュされた文の取出し

暗黙的にキャッシュされた文を取り出すには、文の種類に応じて、prepareStatementまたはprepareCallメソッドをコールします。

次のコードでは、prepareStatementメソッドを使用して、キャッシュからpstmtを取り出します。

pstmt = conn.prepareStatement ("UPDATE emp SET ename = ? WHERE rowid = ?");
20.2.3.1 文の割当ておよび暗黙的文キャッシュで使用されるメソッド

文を割り当てたり、暗黙的にキャッシュされた文を取り出したりするメソッドについて、表20-2で説明します。

表20-2 文の割当ておよび暗黙的文キャッシュで使用されるメソッド

メソッド 暗黙的文キャッシュの機能

prepareStatement

目的のキャッシュされたOraclePreparedStatementオブジェクトを検索して戻すキャッシュ検索を実行します。一致するオブジェクトが見つからない場合は、新しいOraclePreparedStatementオブジェクトを割り当てます。

prepareCall

目的のキャッシュされたOracleCallableStatementオブジェクトを検索して戻すキャッシュ検索を実行します。一致するオブジェクトが見つからない場合は、新しいOracleCallableStatementオブジェクトを割り当てます。

例20-1は、暗黙的文キャッシュを有効にする方法を示すサンプル・コードです。

例20-1 暗黙的文キャッシュの使用

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.pool.OracleDataSource;
public class TestJdbc
{
  /**
   * Get a Connection, prepare a statement, execute a query, fetch the results, close the connection.
   * @param ods the DataSource used to get the connection.
   */
  private static void doSQL( DataSource ods ) throws SQLException
  {
    final String SQL = "select username from all_users";
    OracleConnection  conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try
    {
      conn = (OracleConnection) ods.getConnection();
      System.out.println( "Connection:" + conn );
      System.out.println( "Connection getImplicitCachingEnabled:" + conn.getImplicitCachingEnabled() );
      System.out.println( "Connection getStatementCacheSize:" + conn.getStatementCacheSize() );
      ps = conn.prepareStatement( SQL );
      System.out.println( "PreparedStatement:" + ps );
      rs = ps.executeQuery();
      while ( rs.next() )
      {
        String owner = rs.getString( 1 );
        System.out.println( owner );
      }
    }
    finally
    {
      if ( rs != null )
      {
        rs.close();
      }
      if ( ps != null )
      {
        ps.close();
      conn.close();
    }
  }
  }
  public static void main( String[] args )
  {
    try
    {
      OracleDataSource ods =  new OracleDataSource();
      ods.setDriverType( "thin" );
      ods.setServerName( "localhost" );
      ods.setPortNumber( 5221 );
      ods.setServiceName( "orcl" );
      ods.setUser( "HR" );
      ods.setPassword( "hr" );
      ods.setConnectionCachingEnabled( true );
      ods.setImplicitCachingEnabled( true );
      Properties cacheProps = new Properties();
      cacheProps.put( "InitialLimit", "1" );
      cacheProps.put( "MinLimit", "1" );
      cacheProps.put( "MaxLimit", "5" );
      cacheProps.put( "MaxStatementsLimit", "50" );
      ods.setConnectionCacheProperties( cacheProps );
      System.out.println( "DataSource getImplicitCachingEnabled: " + ods.getImplicitCachingEnabled() );
      for ( int i = 0; i < 5; i++ )
      {
        doSQL( ods );
      }
    }
    catch ( Exception ex )
    {
      ex.printStackTrace();
    }
  }
}

20.2.4 明示的文キャッシュの使用方法について

明示的文キャッシュを有効にすると、プリペアド文またはコール可能文を明示的にキャッシュできます。明示的文キャッシュでは、次のステップが行われます。

  1. 明示的文キャッシュを有効にします。

  2. 標準メソッドの1つを使用して文を割り当てます。

  3. 文を明示的にキャッシュするには、closeWithKeyメソッドを使用して、キーを付けてその文をクローズします。

  4. 明示的にキャッシュされた文を取り出すには、適切なWithKeyメソッドをコールして、適切なキーを指定します。

  5. オープンしている、明示的にキャッシュされた文を再キャッシュするには、closeWithKeyメソッドを使用して文を再度クローズします。キャッシュされた文をクローズするたびに、そのキーを使用して文を再キャッシュします。

明示的なキャッシュのための文の割当て

明示的文キャッシュに文を割り当てるには、通常createStatementprepareStatementまたはprepareCallメソッドを使用します。

次のコードでは、pstmtと呼ばれる新しい文オブジェクトを割り当てます。

PreparedStatement pstmt =
   conn.prepareStatement ("UPDATE emp SET ename = ? WHERE rowid = ?");

文の明示的なキャッシュ

割り当てられた文を明示的にキャッシュするには、文オブジェクトのcloseWithKeyメソッドをコールして、キーを指定します。キーは、ユーザーが指定する任意のJava Stringです。closeWithKeyメソッドは、文をそのままキャッシュします。つまり、データ、状態およびメタデータはクリアされずに保持されます。

次のコードでは、"mykey"キーを使用してpstmt文をキャッシュします。

((OraclePreparedStatement)pstmt).closeWithKey ("mykey");

明示的にキャッシュされた文の取出し

明示的にキャッシュされた文を再度コールするには、文の種類によって、getStatementWithKeyまたはgetCallWithKeyメソッドをコールします。

指定したキーを使用して文を取り出す場合は、指定したキーに基づいて、JDBCドライバがキャッシュ内でその文を検索します。一致する文が見つかった場合、一致する文は、状態、データおよびメタデータとともに戻されます。情報は、文が最後にクローズしたときの状態で戻されます。一致する文が見つからない場合は、JDBCドライバでnullが戻されます。

次のコードでは、getStatementWithKeyメソッドで"mykey"キーを使用して、キャッシュからpstmtを再度コールします。pstmt文オブジェクトは"mykey"キーでキャッシュされていました。

pstmt = ((OracleConnection)conn).getStatementWithKey ("mykey");

pstmt文オブジェクトでcreationStateメソッドをコールすると、メソッドはEXPLICITを戻します。

ノート:

明示的にキャッシュされた文を取り出す場合は、キーを指定するときに文の種類に適したメソッドを使用してください。たとえば、prepareStatementメソッドを使用して文を割り当てた場合は、getStatementWithKeyメソッドを使用してキャッシュから文を取り出します。JDBCドライバは、戻す文の型を検証しません

20.2.4.1 明示的にキャッシュされた文を取り出す場合に使用するメソッド

明示的にキャッシュされた文を取り出す場合に使用するメソッドについて、表20-3で説明します。

表20-3 明示的にキャッシュされた文を取り出す場合に使用するメソッド

メソッド 明示的文キャッシュの機能

getStatementWithKey

キャッシュからプリペアド文を取り出すのに必要なキーを指定します。

getCallWithKey

キャッシュからコール可能文を取り出すのに必要なキーを指定します。

20.3 文オブジェクトの再利用について

JDBC 3.0の仕様で導入された文プーリングでは、アプリケーションは、Connectionオブジェクトの使用と同様にしてPreparedStatementオブジェクトを再利用することができます。PreparedStatementオブジェクトは、複数の論理接続が透過的に再利用できます。

この項の内容は次のとおりです。

ノート:

Oracle JDBCドライバでは、文のプーリングをサポートするために、暗黙的文キャッシュを使用します。

20.3.1 プールされた文の使用について

StatementインタフェースからisPoolableメソッドをコールすることによって、データソースが文プーリングをサポートするかどうかを認識できます。戻り値がtrueの場合、アプリケーションはPreparedStatementオブジェクトがプールされていることを認識しています。アプリケーションはまた、StatementインタフェースからsetPoolableメソッドをコールすることによって、文がプールされるようにするかどうかを指定することができます。

プールされた文の再利用は、アプリケーションに対して完全に透過的である必要があります。つまり、PreparedStatementオブジェクトが文プーリングに関与するかどうかにかかわらず、アプリケーション・コードが同じままであることが必要です。アプリケーションがPreparedStatementオブジェクトをクローズした場合、再利用する際はConnection.prepareStatementメソッドをコールする必要があります。

ノート:

アプリケーションは、文がどのようにプールされるかを、直接的に制御しません。文のプールはPooledConnectionオブジェクトに関連付けられます。このオブジェクトの動作は、それを作成したConnectionPoolDataSourceオブジェクトのプロパティによって決定されます。

20.3.2 プールされた文のクローズについて

アプリケーションがプールされた文をクローズする方法は、プールされていない文をクローズする方法と完全に同じです。プールされた文であってもプールされていない文であっても、一度クローズされると、その文をアプリケーションが使用することはできず、再利用しようとすると例外がスローされる原因になります。認識できる唯一の相違点は、プールされる物理文をアプリケーションが直接クローズすることができないということです。その操作はプール・マネージャが行います。メソッドPooledConnection.closeAllは、指定の物理接続上でオープンしている文をすべてクローズします。これにより、それらの文に関連付けられているリソースが解放されます。

次のメソッドは、プールされた文をクローズすることができます。

  • close

    このjava.sql.Statementインタフェース・メソッドはアプリケーションによってコールされます。文がプールされる場合、アプリケーションが使用する論理文はクローズされますが、プールされた物理文はクローズされません。

  • close

    このjava.sql.Connectionインタフェース・メソッドはアプリケーションによってコールされます。このメソッドは、文を使用する接続がプールされるかどうかに応じて、異なる動作をします。

    • プールされていない接続

      このメソッドは、物理接続が作成したすべての接続とすべての文をクローズします。こうする必要があるのは、外部的に管理されているリソースをいつ解放できるかは、ガーベジ収集メカニズムで検出できないためです。

    • プールされた接続

      このメソッドは論理接続とそれが戻した論理文をクローズしますが、その基礎となるPooledConnectionオブジェクトや、関連付けられているプールされた文はオープンされた状態に残します。

  • PooledConnection.closeAll

    このメソッドは、PooledConnectionオブジェクトによってプールされる物理文をすべてクローズするために接続プール・マネージャによってコールされます。

20.4 結果セット・キャッシュについて

アプリケーションでは、データベースに問合せを繰返し送信することがあります。繰返しの問合せのレスポンス時間を改善するには、問合せの結果、問合せフラグメントおよびPL/SQLファンクションをメモリーにキャッシュできます。結果キャッシュには、すべてのセッションにわたって共有される問合せの結果が格納されます。これらの問合せを繰返し実行すると、結果がキャッシュ・メモリーから直接取り出されます。

ノート:

結果セットが非常に大きい場合、サイズ制限のためにキャッシュされない場合があります。

結果が問合せ結果キャッシュに格納されることを示すには、問合せまたは問合せフラグメントに結果キャッシュのヒントで注釈を付ける必要があります。

問合せ結果セットは、次の方法でキャッシュできます。

ノート:

  • サーバー側およびクライアント結果セットのキャッシュは、読取り専用または大部分が読取りのデータに最も便利です。非常に動的な結果となる問合せの場合は、パフォーマンスが低下する可能性があります。

  • サーバー側およびクライアント結果セットのキャッシュはどちらも、メモリーを使用します。したがって、非常に大きな結果セットをキャッシュすると、パフォーマンス上の問題が発生する可能性があります。

20.4.1 サーバー側結果セット・キャッシュ

サーバー側結果セット・キャッシュは、Oracle Database 11gリリース1から、JDBC ThinおよびJDBC Oracle Call Interface(OCI)の両方のドライバに対してサポートされるようになりました。サーバー側結果キャッシュは、現在の問合せ、問合せフラグメントおよびPL/SQLファンクションの結果をメモリーにキャッシュし、その問合せ、問合せフラグメントまたはPL/SQLファンクションをその後実行する際に、キャッシュした結果を使用するためのものです。キャッシュした結果はSGAの結果キャッシュ・メモリー部分に存在します。作成に使用されたデータベース・オブジェクトが正常に修正されると、キャッシュ結果は自動的に無効化されます。サーバー側キャッシュには、次の2つのタイプがあります。

  • SQL問合せ結果キャッシュ

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

関連項目:

20.4.2 クライアント側結果セット・キャッシュ

クライアント側結果セット・キャッシュ機能により、クライアント側でのSQL問合せ結果セットのクライアント・メモリーへのキャッシュが可能になります。このようにして、アプリケーションでは、クライアント・メモリーを使用することで、繰返しの問合せのレスポンス時間を改善するためにクライアント側結果セット・キャッシュを利用できます。

この項の内容は次のとおりです。

20.4.2.1 クライアント側結果セット・キャッシュの有効化

Oracle Databaseリリース18cでは、JDBC Thinドライバでクライアント側結果セット・キャッシュがサポートされています。この機能を有効にするには、新しいoracle.jdbc.enableQueryResultCache接続プロパティを使用できます。このプロパティのデフォルト値はtrueで、この機能がデフォルトで有効になっていることを意味します。プロパティをfalseに設定することで、この機能を無効にできます。

ノート:

  • Oracle Database 12cリリース2 (12.2)では、enableQueryResultCacheプロパティはenableResultSetCacheとして使用可能であり、デフォルト値はfalseです。enableResultSetCacheプロパティをtrueに設定することで、この機能を有効にできます。

  • JDBC OCIドライバは、クライアント側結果セット・キャッシュをすでにサポートしています。

この機能を使用するには、次のデータベース初期化パラメータを次のように設定する必要があります。

CLIENT_RESULT_CACHE_SIZE=100M
CLIENT_RESULT_CACHE_LAG=1000 

CLIENT_RESULT_CACHE_SIZEパラメータのこの値は、Thinドライバがキャッシュに使用できるメモリー量を制御します。

読取り専用または大部分が読取りの表に注釈を付けることができるようになり、表のデータをドライバにキャッシュできるようになります。たとえば、RESULT_CACHE(MODE FORCE)です。

キャッシュの対象となる問合せを識別するSQLヒント/*+RESULT_CACHE */も使用できます。

20.4.2.2 クライアント側結果セット・キャッシュの利点

クライアント側結果セット・キャッシュには次のような利点があります。

  • クライアント側結果セット・キャッシュは、アプリケーションに対して完全に透過的です。結果セット・データのキャッシュは、結果セットに影響を与えるすべてのセッションまたはデータベース変更と一致するように維持されています。

  • 表注釈を使用すると、クライアント側の結果セットがJDBCアプリケーションに対して透過的に動作します。そうでない場合、ヒントを使用してこれを有効にします。キャッシュ・ヒットはサーバーへの問合せとラウンドトリップの実行を回避して、結果セットを取得します。このため、サーバーCPUやサーバーI/Oなどのサーバー・リソースにとって、非常に大きなパフォーマンスの節約になります。

    関連項目:

    表注釈およびSQLヒント

  • クライアントの結果キャッシュはプロセス単位であるため、複数のクライアント・セッションで一致するキャッシュ内の結果セットを同時に使用できます。

  • クライアントの結果キャッシュにより、各アプリケーションが独自のカスタム結果セット・キャッシュを持つ必要性が最小限に抑えられます。

  • クライアントの結果キャッシュではクライアント・メモリーが使用され、サーバー・メモリーよりコストが低くなります。

20.4.2.3 JDBCでの使用ガイドライン

結果セット・キャッシュを有効化するには次の3つの方法があります。

ノート:

  • クライアント側結果セット・キャッシュを使用する場合、アプリケーション・レベルでJDBC文キャッシュまたはキャッシュ文を使用する必要があります。

  • SQLヒントは、セッション・パラメータRESULT_CACHE_MODEおよび表注釈よりも優先されます。表注釈FORCEはセッション・パラメータよりも優先されます。

20.4.2.3.1 RESULT_CACHE_MODEパラメータ

RESULT_CACHE_MODEパラメータを使用して、問合せで使用する表の結果キャッシュ・モードを決定できます。ALTER SESSIONおよびALTER SYSTEM文でこの句を使用するか、またはサーバー・パラメータ・ファイル(init.ora)内でこの句を使用して、結果キャッシュを決定します。RESULT_CACHE_MODEパラメータを設定して、SQL問合せ結果キャッシュをすべての問合せで使用するか、SQLヒントまたは表注釈を使用して結果キャッシュ・ヒントで注釈を付けられている問合せのみで使用するかを制御できます。

20.4.2.3.2 表注釈

表注釈を使用して、コードを変更しないで結果キャッシュを有効にできます。ALTER TABLEおよびCREATE TABLE文を使用すると、結果キャッシュ・モードで表に注釈を付けることができます。構文は次のとおりです。

CREATE|ALTER TABLE [<schema>.]<table> ... [RESULT_CACHE (MODE {FORCE|DEFAULT})]

次の例では、CREATE TABLE文で表注釈を使用する方法を示しています。

CREATE TABLE foo (a NUMBER, b VARCHAR2(20)) RESULT_CACHE (MODE FORCE);

次の例では、ALTER TABLE文で表注釈を使用する方法を示しています。

ALTER TABLE foo RESULT_CACHE (MODE DEFAULT);
20.4.2.3.3 SQLヒント

SQLヒントを使用し、/*+ result_cache */または/*+ no_result_cache */のヒントの付いている問合せに注釈を付けることによってキャッシュする問合せを指定できます。たとえば、次のコードを見てください。

String  query  = "select /*+ result_cache */ * from employees where employee_id < : 1";
   ((oracle.jdbc.OracleConnection)conn).setImplicitCachingEnabled(true);
   ((oracle.jdbc.OracleConnection)conn).setStatementCacheSize(10);
   PreparedStatement  pstmt;
   ResultSet rs;
     
    for (int j = 0 ; j < 10 ; j++ )
    {
       pstmt  = conn.prepareStatement (query);
       pstmt.setInt(1,7500);
       rs  = pstmt.executeQuery();
         while (rs.next( ) )
        {     // see the values  }
          rs.close;
          pstmt.close( ) ;
        }
    } 

この例では、クライアント結果キャッシュのヒント/*+ result_cache */が、実際の問合せであるselect * from employees where employee_id < : 1に注釈として付けられています。したがって、問合せは最初にデータベースに対して実行され、その結果セットが、問合せの残り9回の実行用にキャッシュされます。これにより、アプリケーションのパフォーマンスは大幅に向上します。これは主として読取り専用データの場合に便利です。

SQLヒントの例を次に示します。次の例はすべて、dept表が結果キャッシュのために次のコマンドによって注釈を付けられていることを前提にしています。

ALTER TABLE dept result_cache (MODE FORCE);

  • SELECT * FROM employees

    結果セットはキャッシュされません。

  • SELECT * FROM departments

    結果セットはキャッシュされます。

  • SELECT /*+ result_cache */ employee_id FROM employees

    結果セットはキャッシュされます。

  • SELECT /*+ no_result_cache */ department_id FROM departments

    結果セットはキャッシュされません。

  • SELECT /*+ result_cache */ * FROM departments

    問合せヒントは不要ですが、結果セットはキャッシュされます。

  • SELECT e.first_name FROM employees e, departments d WHERE e.department_id = d.department_id

    問合せヒントが使用不可で、すべての表がFORCEとして注釈を付けられていないため、結果セットはキャッシュされません。

ノート:

使用ガイドライン、クライアント・キャッシュの整合性、デプロイ時間の設定、クライアント・キャッシュ統計情報、クライアント結果キャッシュの検証およびOCIクライアント結果キャッシュとサーバー結果キャッシュの詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。