JDBCアプリケーションのチューニング

TimesTen向けにJDBCアプリケーションをチューニングする場合に考慮する必要がある一般原則を示します。

内容は次のとおりです。

準備された文のプールの使用

TimesTenでは、プールされた接続用に、TimesTen ObservableConnectionDSクラスによる準備された文のプールをサポートしています。

これは、TimesTenへのConnectionPoolDataSourceの実装です。文のプールは、アプリケーションに対して透過的であることに注意してください。PreparedStatementオブジェクトは同様に使用(文の準備およびクローズを含む)できます。

準備された文のプールを有効化して、ObservableConnectionDSメソッドsetMaxStatements()をコールすることでプールの文の最大数を指定できます。デフォルトの値は0で、準備された文プールを無効化しています。0より大きい任意の整数値を指定すると、その値を文の最大数として、準備された文のプールを有効化します。設定した後、この値は変更しないでください。

最大プール数に達していないかぎり、準備された文またはコール可能な文は作成時にプールされます。文オブジェクトよりsetPoolable(false)をコールすることによって、準備された文またはコール可能な文をプールから削除できます。文は終了するとプールから削除されます。

ヒント:

準備された文のプールを使用する場合、JDBCは、SQLが(コメントを含めて)同一であれば、オプティマイザ設定などの他の考慮事項に関係なく、その2つの文を同一とみなします。他の点では同一の文に、異なるオプティマイザ・ヒントが適用される可能性がある場合、準備された文のプールは使用しないでください。このシナリオでは、文の実行によって、プールの同一の文が予測不能なオプティマイザ設定で使用されることがあります。

バッチ実行にパラメータの配列を使用

文の実行グループ(バッチとも呼ばれる)を使用してStatementまたはPreparedStatementオブジェクトにaddBatch()およびexecuteBatch()メソッドをコールすることで、パフォーマンスを向上させることができます。

バッチは、INSERTUPDATEDELETEまたはMERGEなどの文のセットで構成されます。(TimesTen ScaleoutではMERGE文はサポートされていません。)SELECTなどの結果セットを返す文は、バッチでは使用できません。文オブジェクトよりaddBatch()をコールすると、バッチにSQL文が追加されます。バッチに関連付けられている一連のSQL文は、executeBatch()メソッドによって実行されます。

PreparedStatementオブジェクトの場合、バッチは異なる入力パラメータ値を使用して繰返し実行される1つの文で構成されます。入力値のセットごとに、必要なsetXXX()コールを使用した後に、addBatch()コールを使用して、バッチを作成します。バッチは、executeBatch()メソッドを介して実行されます。

これらのデータベース操作の理想的なバッチ・サイズは、ユーザー環境の詳細に応じて異なり、判断するにはテストおよび実験が必要です。

ヒント:

TimesTen Classicでは、挿入メカニズムを最適化するために、挿入用に256の正確な倍数であるバッチ・サイズを使用することが重要です。

バッチ文の例を次に示します。

// turn off autocommit
conn.setAutoCommit(false);

Statement stmt = conn.createStatement();
stmt.addBatch("INSERT INTO employees VALUES (1000, 'Joe Jones')");
stmt.addBatch("INSERT INTO departments VALUES (260, 'Shoe')");
stmt.addBatch("INSERT INTO emp_dept VALUES (1000, 260)");

// submit a batch of update commands for execution
int[] updateCounts = stmt.executeBatch();
conn.commit ();

次の例では、準備された文をバッチ化します。

// turn off autocommit
conn.setAutoCommit(false);
// prepare the statement
PreparedStatement stmt = conn.prepareStatement
                         ("INSERT INTO employees VALUES (?, ?)");

// first set of parameters
stmt.setInt(1, 2000);
stmt.setString(2, "Kelly Kaufmann");
stmt.addBatch();

// second set of parameters
stmt.setInt(1, 3000);
stmt.setString(2, "Bill Barnes");
stmt.addBatch();

// submit the batch for execution. Check update counts
int[] updateCounts = stmt.executeBatch();
conn.commit ();

StatementまたはPreparedStatementオブジェクトでは、executeBatch()メソッドは更新回数の配列(前述の例のupdateCounts[])と各文の実行の配列の1要素を返します。各要素の値は次のいずれかになります。

  • 数字は、対応する文の実行によってデータベース内で影響を受ける行の数を示します

  • SUCCESS_NO_INFOは、対応する文の実行に成功したことを示しますが、影響を受けた行数については不明です

  • EXECUTE_FAILEDは、対応する文の実行に失敗したことを示します

    文の実行がEXECUTE_FAILEDのステータスになると、それ以降、文の実行は試行されません

JDBCバッチ更新機能の使用方法の詳細は、次の場所にある、java.sql.StatementインタフェースのJavadoc、とりわけexecuteBatch()メソッドに関する情報を参照してください。

https://docs.oracle.com/javase/8/docs/api/java/sql/package-summary.html

ノート:

連想配列パラメータは、JDBCのバッチの実行ではサポートされていません(「連想配列の使用」を参照してください。)

TimesTenデータ行のバルク・フェッチ

TimesTenで提供されている拡張を使用すると、アプリケーションで複数のデータ行をフェッチできます。

大量のデータを取得するアプリケーションの場合、複数行のフェッチによってパフォーマンスを大幅に向上させることができます。ただし、コミット読取り分離レベルが使用される場合は、アプリケーションですべてのデータが取得されるまで、取得されるすべての行にロックが設定されるため、同時実行性は低下します。「複数のデータ行のフェッチ」を参照してください。

ResultSetのメソッドgetString()の使用は慎重に

Javaの文字列は不変的であるため、ResultSetメソッドgetString()は、(基礎となるC文字列からUnicode文字列への変換に加えて、)新しい文字列用の領域を確保する必要があり、高コストのコールとなっています。

また、必要時以外は、byteintなどの基本的な数値型でgetString()をコールしないでください。たとえば、整数列の場合、getInt()をコールする方が大幅に高速に処理が実行されます。

データ型の変換の回避

TimesTenの命令パスは非常に短いため、データ変換による短時間の遅延によっても、トランザクション時間が大幅に増加する可能性があります。

基礎となるデータベース内のデータのデータ型に対するResultSetオブジェクトには、適切なgetXXX()メソッドを使用します。たとえば、データのデータ型がDOUBLEである場合、JDBCドライバでのデータ変換を避けるために、getDouble()をコールする必要があります。同様に、SQL文の入力パラメータには、PreparedStatementオブジェクトで、適切なsetXXX()メソッドを使用します。たとえば、PreparedStatementを使用してCHAR列にデータを挿入する場合は、setString()を使用する必要があります。

接続、文および結果セットのクローズ

パフォーマンスを向上させるには、接続、文および結果セット・インスタンスなどのJDBCオブジェクトの使用後は常にクローズします。

例:

    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    try {
      // create connections, execute statements, etc.
      // Handle any errors
    } catch (SQLException ex) {
      // See Error Handling.
    }
    finally {
      // Close JDBC objects such as connections, statements, result sets, etc.
      if (rs != null) {
        try {
          rs.close();
        }
        catch(SQLException finalex) {
          // See Error Handling.
        }        
      }
      if (stmt != null) {
        try {
          stmt.close();
        }
        catch(SQLException finalex) {
          // See Error Handling.
        }
      }
      // Always, close the connection to TimesTen
      if (conn != null) {
        try {
          conn.close();
        }
        catch(SQLException finalex) {
       // See Error Handling.
        }
      }

問合せの最適化

TimesTenでは、true設定によって問合せのパフォーマンスを最適化するために、TimesTenConnectionメソッドのsetTtPrefetchClose()が提供されています。

「問合せのパフォーマンスの最適化」を参照してください。