アダプティブ バッファリングの使用

JDBC ドライバーのダウンロード

アダプティブ バッファリングは、サーバー カーソルのオーバーヘッドを発生させることなく、あらゆる種類の大きな値のデータを取得できるように設計されています。 アプリケーションでは、ドライバーによってサポートされるすべてのバージョンの SQL Server でアダプティブ バッファリング機能を使用できます。

通常、SQL Server 用 Microsoft JDBC ドライバー がクエリを実行するときは、すべての結果をサーバーからアプリケーション メモリに取り出します。 この方法では、SQL Server でのリソースの消費が最小化されますが、非常に大きな結果を生成するクエリの場合は、JDBC アプリケーションで OutOfMemoryError がスローされることがあります。

アプリケーションで非常に大きな結果を処理できるようにするために、SQL Server 用 Microsoft JDBC ドライバー はアダプティブ バッファリングを提供しています。 ドライバーでアダプティブ バッファリングを使用すると、ステートメントの実行結果を SQL Server から取得する処理が、すべて一度にではなく、アプリケーションの必要に応じて行われます。 また、アプリケーションからアクセスできなくなった結果は、ドライバーによって直ちに破棄されます。 アダプティブ バッファリングは次のような場合に効果的です。

  • クエリが非常に大きな結果セットを生成する: アプリケーションでは、メモリに格納できる行よりも多くの行を生成する SELECT ステートメントを実行できます。 以前のリリースでは、OutOfMemoryError を避けるために、サーバー カーソルを使用する必要がありました。 アダプティブ バッファリングは、サーバー カーソルを使用することなく、任意の大きな結果セットを順方向専用かつ読み取り専用で渡せるようにします。

  • クエリが非常に大きなSQLServerResultSet列またはSQLServerCallableStatementOUT パラメーター値を生成する: アプリケーションが、アプリケーション メモリに完全に格納できない過剰に大きな単一の値 (列または OUT パラメーター) を取得する場合があります。 アダプティブ バッファリングを使用すると、クライアント アプリケーションで getAsciiStream メソッド、getBinaryStream メソッド、または getCharacterStream メソッドを使用して、そのような値をストリームとして取得できます。 アプリケーションは、ストリームから読み取るときと同じようにして、SQL Server から値を取得します。

注

アダプティブ バッファリングでは、必要な量のデータだけが、JDBC ドライバーによってバッファリングされます。 ドライバーにバッファーのサイズを制御したり制限したりするためのパブリック メソッドは備わっていません。

アダプティブ バッファリングの設定

JDBC Driver 2.0 以降では、ドライバーの既定の動作は "adaptive" です。 つまり、アプリケーションから明示的に要求しなくても、アダプティブ バッファリングの動作が適用されます。 ただし、バージョン 1.2 リリースでは、"full" が既定のバッファリング モードであるため、アプリケーションから明示的にアダプティブ バッファリング モードを要求する必要があります。

アプリケーションがステートメントの実行でアダプティブ バッファリングを使用するように要求できる方法は 3 つあります。

  • アプリケーションで、接続プロパティ responseBuffering を "adaptive" に設定できます。 接続プロパティの設定の詳細については、「接続プロパティの設定」を参照してください。

  • アプリケーションで、SQLServerDataSource オブジェクトの setResponseBuffering メソッドを使用して、その SQLServerDataSource オブジェクトを通じて作成されたすべての接続の応答バッファリング モードを設定できます。

  • アプリケーションで、SQLServerStatement クラスの setResponseBuffering メソッドを使用して、特定のステートメント オブジェクトの応答バッファリング モードを設定できます。

JDBC Driver Version 1.2 を使用している場合、setResponseBuffering メソッドを使用するには、Statement オブジェクトを SQLServerStatement クラスにキャストする必要があります。 「大きなデータを読み取るサンプル」および「ストアド プロシージャで大きなデータを読み取るサンプル」のコード例は、この古い使用方法を示しています。

ただし、JDBC ドライバー Version 2.0 では、実装されているクラス階層を意識することなく、isWrapperFor メソッドおよび unwrap メソッドを使用して、ベンダー固有の機能にアクセスできます。 コード例については、「大きなデータを更新するサンプル」を参照してください。

アダプティブ バッファリングによる大きなデータの取得

get<Type>Stream メソッドを使用して大きな値を 1 回読み取り、SQL Server によって返された順序で ResultSet 列および CallableStatement OUT パラメーターにアクセスする場合、アダプティブ バッファリングにより、結果を処理するときのアプリケーション メモリの使用量を最小限に抑えることができます。 アダプティブ バッファリングを使用すると、次のようになります。

  • SQLServerResultSet クラスおよび SQLServerCallableStatement クラスで定義されている get<Type>Stream メソッドは、既定では一度しか読み取れないストリームを返しますが、これらのストリームはアプリケーションによってマークされている場合はリセットできます。 アプリケーションでストリームの reset を行う必要がある場合、まずそのストリームに対して mark メソッドを呼び出す必要があります。

  • SQLServerClob クラスおよび SQLServerBlob クラスで定義されている get<Type>Stream メソッドは、mark メソッドを呼び出さなくても、常にストリームの先頭位置に戻すことができるストリームを返します。

アプリケーションでアダプティブ バッファリングを使用する場合、get<Type>Stream メソッドによって取得される値は、1 回だけ取得できます。 同じオブジェクトの get<Type>Stream メソッドを呼び出した後に、同じ列またはパラメーターで任意の get<Type> メソッドを呼び出すと、"このデータはアクセスされており、この列またはパラメーターに対しては使用できません" という意味のメッセージで例外がスローされます。

注

ResultSet の処理中に ResultSet.close() を呼び出すと、残りのすべてのパケットを読み取って破棄するために Microsoft JDBC Driver for SQL Server が必要になります。 クエリから大きなデータ セットが返された場合、特にネットワーク接続の速度が遅い場合、この処理にはかなりの時間がかかることがあります。

アダプティブ バッファリングの使用に関するガイドライン

アプリケーションによるメモリ使用量を最小限に抑えるには、開発者は次の重要なガイドラインに従う必要があります。

  • アプリケーションが非常に大きな結果セットを処理できるようにするために、接続文字列プロパティ selectMethod=cursor を使用しないようにします。 アダプティブ バッファリング機能を使用すると、アプリケーションがサーバー カーソルを使用することなく、非常に大きな順方向専用の読み取り専用結果セットを処理することが可能になります。 selectMethod=cursorを設定すると、その接続によって生成されるすべてのフォワードオンリー・読み取り専用の結果セットが影響を受けます。 つまり、わずかな行数の短い結果セットを定期的に処理するようなアプリケーションでは、結果セットごとにサーバー カーソルを作成し、読み取って、閉じる操作を繰り返すことになって、クライアント側とサーバー側の両方でリソース消費が (selectMethod を cursor に設定しなかった場合と比較して) 増えることになります。

  • サイズの大きいテキストまたはバイナリ値をストリームとして読み取るには、getBlob メソッドまたは getClob メソッドの代わりに、getAsciiStream メソッド、getBinaryStream メソッド、または getCharacterStream メソッドを使用します。 Version 1.2 リリース以降の SQLServerCallableStatement クラスには、この目的のための新しい get<Type>Stream メソッドがあります。

  • 大きな値が入る可能性のある列は、SELECT ステートメント内の列リストの最後に配置し、SQLServerResultSet の get<Type>Stream メソッドを使用して、選択した順序で列にアクセスするようにしてください。

  • 大きな値を含む可能性がある OUT パラメーターは、SQLServerCallableStatement の作成に使用する SQL のパラメーターの一覧の最後で宣言します。 また、SQLServerCallableStatement の get<Type>Stream メソッドを使用して、OUT パラメーターに宣言された順序どおりにアクセスするようにしてください。

  • 同じ接続で複数のステートメントを同時に実行しないでください。 前のステートメントの結果を処理する前に別のステートメントを実行すると、処理されない結果がアプリケーションのメモリにバッファリングされることがあります。

  • 次のように、responseBuffering=adaptive の代わりに selectMethod=cursor を使用すると有用な場合があります。

    • ユーザー入力の後で 1 つずつ行を読み取るなど、順方向専用、読み取り専用の結果セットを少しずつ処理するようなアプリケーションでは、responseBuffering=adaptive の代わりに selectMethod=cursor を使用すると、SQL Server によるリソース使用量が少なくて済みます。

    • 同じ接続で順方向専用、読み取り専用の複数の結果セットを同時に処理するようなアプリケーションでは、responseBuffering=adaptive の代わりに selectMethod=cursor を使用することで、ドライバーがこれらの結果セットを処理する際に必要となるメモリ量を減らすことができます。

    どちらのケースも、サーバー カーソルを作成し、読み取って、閉じるという処理のオーバーヘッドを考慮する必要があります。

スクロール可能な結果セットと順方向専用の更新可能な結果セットの推奨事項を以下に補足します。

  • スクロール可能な結果セット : 行をブロック単位でフェッチする場合、常に SQLServerResultSet オブジェクトの getFetchSize メソッドで指定された行数がメモリに読み込まれます。これは、アダプティブ バッファリングが有効になっていたとしても変わりません。 スクロールによって OutOfMemoryError が発生した場合は、フェッチされる行数を減らすことによって対処できます。フェッチ サイズの行数を減らすには、SQLServerResultSet オブジェクトの setFetchSize メソッドを呼び出します。必要であれば、行数を 1 に設定することも検討してください。 それでも OutOfMemoryError を回避できない場合は、あまり大きな列がスクロール可能な結果セットに含まれないようにします。

  • 順方向専用で更新可能な結果セットでは、行のブロックをフェッチする際、接続でアダプティブ バッファリングが有効になっている場合でも、通常、ドライバーは SQLServerResultSet オブジェクトの getFetchSize メソッドで指定された行数をメモリに読み込みます。 SQLServerResultSet オブジェクトの next メソッドを呼び出すと OutOfMemoryError が発生する場合は、フェッチされる行数を減らすことによって対処できます。フェッチ サイズの行数を減らすには、SQLServerResultSet オブジェクトの setFetchSize メソッドを呼び出します。必要であれば、行数を 1 に設定することも検討してください。 SQLServerStatement オブジェクトの setResponseBuffering メソッドを "adaptive" パラメーターで呼び出した後、ステートメントを実行することによって、行のバッファリングを強制的に抑制することもできます。 結果セットはスクロールできないため、アプリケーションから、いずれかの get<Type>Stream メソッドで大きな列の値にアクセスした場合、アプリケーションが読み取りを始めると直ちに、ドライバーが、順方向専用、読み取り専用の結果セットの場合とまったく同じように、その値を破棄します。