この章では、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つの文で構成されます。入力値のセットごとに、必要なset
XXX
()
コールを使用した後に、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.html
http://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
オブジェクトには、適切なget
XXX()
メソッドを使用します。たとえば、データのデータ型がDOUBLE
である場合、JDBCドライバでのデータ変換を避けるために、getDouble()
をコールする必要があります。同様に、SQL文の入力パラメータには、PreparedStatement
オブジェクトで、適切なset
XXX()
メソッドを使用します。たとえば、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
を使用する場合は、コールバック・スレッド自体のメッセージに応答する必要があります。「更新の受信および処理」を参照してください。