この章では、TimesTenデータベース上で最適に実行されるようにJavaアプリケーションをチューニングする方法のヒントを示します。より一般的なチューニングのヒントについては、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のTimesTen Databaseのパフォーマンス・チューニングに関する項を参照してください。
この章は、次の内容で構成されています。
この項では、TimesTen用のJDBCアプリケーションをチューニングする場合に考慮する必要がある一般的な方針について説明します。内容は次のとおりです。
TimesTenでは、プールされた接続用に、TimesTen ObservableConnectionDSクラスによる準備された文のプール(JDBC 3.0の仕様を参照)をサポートしています。これは、TimesTenへのConnectionPoolDataSourceの実装です。文のプールは、アプリケーションに対して透過的であることに注意してください。PreparedStatementオブジェクトは同様に使用(文の準備およびクローズを含む)できます。
準備された文のプールを有効化して、ObservableConnectionDSメソッドsetMaxStatements()をコールすることでプールの文の最大数を指定できます。デフォルトの値は0で、準備された文プールを無効化しています。0より大きい任意の整数値を指定すると、その値を文の最大数として、準備された文のプールを有効化します。設定した後、この値は変更しないでください。
最大プール数に達していないかぎり、準備された文またはコール可能な文は作成時にプールされます。Java 6では、文オブジェクトよりsetPoolable(false)をコールすることによって、準備された文またはコール可能な文をプールから削除できます。文は終了するとプールから削除されます。
|
重要: 準備された文のプールを使用する場合、JDBCは、SQLが(コメントを含めて)同一であれば、オプティマイザ設定などの他の考慮事項に関係なく、その2つの文を同一とみなします。他の点では同一の文に、異なるオプティマイザ・ヒントが適用される可能性がある場合、準備された文のプールは使用しないでください。このシナリオでは、文の実行によって、プールの同一の文が予測不能なオプティマイザ設定で使用されることがあります。 |
文の実行グループ(バッチとも呼ばれる)を使用してStatementまたはPreparedStatementオブジェクトにaddBatch()およびexecuteBatch()メソッドをコールすることで、パフォーマンスを向上させることができます。
バッチは、INSERT、UPDATE、DELETEまたはMERGEなどの文のセットで構成されます。SELECTなどの結果セットを返す文は、バッチでは使用できません。文オブジェクトよりaddBatch()をコールすると、バッチにSQL文が追加されます。バッチに関連付けられている一連のSQL文は、executeBatch()メソッドによって実行されます。
PreparedStatementオブジェクトの場合、バッチは異なる入力パラメータ値を使用して繰返し実行される1つの文で構成されます。入力値のセットごとに、必要なsetXXX()コールを使用した後に、addBatch()コールを使用して、バッチを作成します。バッチは、executeBatch()メソッドを介して実行されます。
TimesTenでは、TimesTen 11gリリース2(11.2.2)に次のバッチ・サイズを推奨します。
INSERT文に256
UPDATE文に31
DELETE文に31
MERGE文に31
例5-1 文へのバッチ
// 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 ();
例5-2 準備された文へのバッチ
// 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()メソッドは更新回数の配列(前述の例5-1および例5-2のupdateCounts[])と各文の実行の配列の1要素を返します。各要素の値は次のいずれかになります。
数字は、対応する文の実行によってデータベース内で影響を受ける行の数を示します
SUCCESS_NO_INFOは、対応する文の実行に成功したことを示しますが、影響を受けた行数については不明です
EXECUTE_FAILEDは、対応する文の実行に失敗したことを示します
文の実行がEXECUTE_FAILEDのステータスになると、それ以降、文の実行は試行されません
JDBCバッチ更新機能の使用方法の詳細は、次の場所にある、Javadocのjava.sql.Statementインタフェース(特に、executeBatch()メソッド)に関する情報を参照してください(1つ目はJava 6用で2つ目はJava 5.0用です)。
http://docs.oracle.com/javase/6/docs/api/java/sql/package-summary.htmlhttp://docs.oracle.com/javase/1.5.0/docs/api/java/sql/package-summary.html
TimesTenで提供されている拡張を使用すると、アプリケーションで複数のデータ行をフェッチできます。大量のTimesTenデータを取得するアプリケーションの場合、複数行のフェッチによってパフォーマンスを大幅に向上させることができます。ただし、コミット読取り分離レベルが使用される場合は、アプリケーションですべてのデータが取得されるまで、取得されるすべての行にロックが設定されるため、同時実行性は低下します。この機能の詳細は、「複数のデータ行のフェッチ」を参照してください。
Javaの文字列は不変的であるため、ResultSetメソッドgetString()は、(基礎となるC文字列からUnicode文字列への変換に加えて、)新しい文字列用の領域を確保する必要があり、高コストのコールとなっています。
また、必要時以外は、byteやintなどの基本的な数値型でgetString()をコールしないでください。たとえば、整数列の場合、getInt()をコールする方が大幅に高速に処理が実行されます。
TimesTenの命令パスは非常に短いため、データ変換による短時間の遅延によっても、トランザクション時間が大幅に増加する可能性があります。
基礎となるデータベース内のデータのデータ型に対してのResultSetオブジェクトには、適切なgetXXX()メソッドを使用します。たとえば、データのデータ型がDOUBLEである場合、JDBCドライバでのデータ変換を避けるために、getDouble()をコールする必要があります。同様に、SQL文の入力パラメータには、PreparedStatementオブジェクトで、適切なsetXXX()メソッドを使用します。たとえば、PreparedStatementを使用してCHAR列にデータを挿入する場合は、setString()を使用する必要があります。
パフォーマンスを向上させるには、接続、文および結果セット・インスタンスなどのJDBCオブジェクトの使用後は常にクローズします。例5-3に典型的な使用例を示します。
例5-3 接続、文、結果セットのクローズ
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// create connections, execute statements, etc.
// Handle any errors
} catch (SQLException ex) {
// See "Handling errors".
}
finally {
// Close JDBC objects such as connections, statements, result sets, etc.
if (rs != null) {
try {
rs.close();
}
catch(SQLException finalex) {
// See "Handling errors".
}
}
if (stmt != null) {
try {
stmt.close();
}
catch(SQLException finalex) {
// See "Handling errors".
}
}
// Always, close the connection to TimesTen
if (conn != null) {
try {
conn.close();
}
catch(SQLException finalex) {
// See "Handling errors".
}
}
この項では、JMS/XLA APIを使用するアプリケーションに固有のパフォーマンス・チューニングのヒントを示します。JMS/XLAでは、オーバーヘッドが発生するため、C XLA APIを使用した場合より低速となります。C APIでは、レコードがユーザーにバッチで戻されます。JMSモデルでは、オブジェクトがインスタンス化され、MessageListenerメソッドonMessage()に対するコールバックで各レコードが1つずつ示されます。高パフォーマンスのアプリケーションでは、チューニングを行ってこのオーバーヘッドの一部を回避できます。
この項の内容は次のとおりです。
トランザクション・ログを読み取るJMSレイヤーの基礎となるコードは、オブジェクト/行をユーザーに示す前にできるかぎり多くの行をフェッチ可能な場合、より効率的になります。プリフェッチの量は、xlaPrefetchパラメータが指定されたjmsxla.xml構成ファイルで制御されます。プリフェッチ数は、100、1000などの大きい値に設定します。
JMS/XLAでは、更新の確認によってブックマークが移動し、システム表が更新されます。確認の発行前は、いくつかの更新が検出されるまで待機することで、通常はアプリケーションのパフォーマンスを向上させることができます。次のいずれかのモードで、確認の頻度を制御できます。(関連情報は、「XLA応答モード」を参照してください。)
DUPS_OK_ACKNOWLEDGEでは、xlaprefetch設定に従ってJMS/XLAはレコードをプリフェッチし、プリフェッチされたブロックの最後のレコードが読み取られると、応答は自動的に送信されます。
CLIENT_ACKNOWLEDGEでは、希望に応じて、MapMessageインスタンスでacknowledge()メソッドを手動でコールします。
確認の頻度の適切な選択は、アプリケーション・ロジックによって決まります。たとえば、100の更新ごとに確認が正常に使用されてきました。ただし、トレードオフがあることに注意してください。確認はXLAログの保持に影響を与え、確認の頻度が低すぎると、好ましくないログ・ファイルの蓄積につながることがあります。(「XLAブックマークおよびトランザクション・ログの保持」も参照してください。)
|
注意: DUPS_OK_ACKNOWLEDGEまたはCLIENT_ACKNOWLEDGEモードでは、リーダー・アプリケーションで同じレコード・セットが複数回戻されることを許容できる必要があります。 |
同期インタフェースは、イベント率が低いアプリケーションと、AUTO_ACKNOWLEDGEまたはDUPS_OK_ACKNOWLEDGE応答モードを許容できるアプリケーションにのみ適しています。CLIENT_ACKNOWLEDGE応答モードを必要とするアプリケーションと、イベント率が高いアプリケーションでは、更新を受信するために非同期インタフェースを使用する必要があります。それらのアプリケーションで応答モードとしてCLIENT_ACKNOWLEDGEを使用する場合は、コールバック・スレッド自体のメッセージに応答する必要があります。「更新の受信および処理」を参照してください。