本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

DB2 UDB EEE 上での Javaを使用したハイパフォーマンス挿入

Krishnakumar PoolothInfosys Technologies Limited
vinu2.jpg
Kishnakumar Pooloth 氏は、Infosys Technologies 社 (http://www.infy.com) のテクニカル・スペシャリスト。オブジェクト・デザイン、コンポーネント・テクノロジー、データベース最適化、および J2EE のエンタープライズ・クラス・アプリケーションの開発の経験を有す。DB2 UDB アプリケーション開発の IBM 認定ソリューション・エキスパートである。インドのカリカット大学から電子通信工学の学位を取得。 メール・アドレス: krishnakumarp@infy.com

概要: DB2 UDB EEE 上での Javaを使用したハイパフォーマンス挿入

日付:  2002年 4月
レベル:  中級 この記事の原文:  英語
アクティビティー: 2810 ビュー
お気軽にご意見・ご感想をお寄せください: 


はじめに

典型的な意思決定支援システム (DSS) では大量データの定期的なロードや挿入が行われます。大規模 DSS は通常は区分化環境で展開されます。JavaTM プログラミング言語が広く普及しているため、この記事では、DB2® ユニバーサル・データベースのバッファー化挿入オプションを Java から活用して、区分化環境における挿入集中型のワークロードのパフォーマンスを最大化する方法を解説します。

この記事は、Java、SQLJ、および JDBC についてある程度理解している読者を対象に書かれています。この記事で説明する概念が該当するのは、DB2 UDB EEE、すなわちデータベース区分化をサポートするバージョンの UDB のみであることに注意してください。



JDBC と SQLJ の比較?

JDBC テクノロジーは、実質的にあらゆる種類の表形式データ・ソースに対する Java プログラミング言語からのアクセスを可能にする API です。DBMS の種類を超えて広範囲の SQL データベースへの接続を提供します。JDBC API により、エンタープライズ・データへのアクセスを必要とする最新鋭クロス・プラットフォーム・アプリケーションで、Java プラットフォームの強みである「1 度作成すればどこでも稼動する」という特性を活用できます。

SQLJ は SQL アクセスを Java でコーディングする ANSI 標準の方法です。SQLJ は JDBC より簡潔で記述も簡単で、コンパイル時のスキーマ妥当性と構文のチェック機能も備えているためデバッグも容易です。この方式では、SQL ステートメントは Java プログラム・コード内に組み込まれ、SQLJ プリコンパイラーによって組み込み SQL ステートメントは Java メソッド呼び出しに変換されます。しかし、SQLJ プリコンパイラーで生成されたコードは必ずしも最適化されていません。SQLJ の詳細については、「SQLJ チュートリアル」を参照してください。



区分化データベースのパワー

データは複数のデータベース区画にわたって分割されるため、複数の物理ノード上の複数プロセッサーのパワーを活用してユーザー要求を満たすことができます。データ取り出しおよび更新要求は、自動的に副要求に分割され、適切なデータベース区画間で並列に実行されます。データベースが複数データベース区画に区分化されるという事実は、SQL ステートメントを発行する側のアプリケーションには透過的です。

アプリケーションとの対話は、そのアプリケーションに対するコーディネーター・ノードとして知られる 1 つのデータベース区画を通して行われます。コーディネーターはアプリケーションと同じデータベース区画で稼動するか、リモート・アプリケーションの場合はそのアプリケーションが接続されているデータベース区画で稼動します。どのデータベース区画もコーディネーター・ノードとして機能できます。区分化データベースの詳細は、「スケーラビリティーのためのクラスタリング」を参照してください。

DB2 は区分化環境で最高のパフォーマンスを達成するために、特別なプログラミング機能をいくつか備えています。バッファー化挿入はその 1 つで、意思決定支援システムに典型的な挿入集中型ワークロードのパフォーマンスを大幅に改善できるテクニックです。

この記事では、次の内容を扱います。

  • バッファー化挿入について、詳細を把握する。
  • SQLJ ベースの表インターフェース・クラスを作成する。わかりやすくするために、このクラスは表へのデータ挿入のインターフェースだけをサポートします。
  • パフォーマンスを改善するテクニックとして、RTStatement オブジェクト再利用を説明する。
  • JDBC、基本 SQLJ、およびコミット頻度の変更に RTStatement 再利用を用いた SQLJ のパフォーマンスをベンチマーク・テストする。また、バッファー化挿入での行の長さの影響も検証します。


バッファー化挿入の概要

区分化環境では、DB2 UDB は表待ち行列を活用し、挿入する行をバッファリングできます。DSS などの挿入集中型のアプリケーションでは、この機能によって大幅にパフォーマンスが向上します。バッファー化挿入を使用するには、アプリケーションは INSERT BUF オプションを有効にして準備またはバインドされる必要があります。単純な挿入とバッファー化挿入の違いを次に説明します。



区分化データベースでの単純な挿入

区分化環境における単純なデータベース挿入 (バッファリングなし) に対するイベント・フローは、図 1 に示すとおりです。


図 1. 区分化環境での単純な挿入処理

  1. コーディネーター・エージェントは、クライアント・アプリケーションから行を受け取る。
  2. コーディネーターはそのノードにあるデータベース・マネージャーに受け取った行を渡す。
  3. データベース・マネージャーは区分化キー値にハッシング・ロジックを適用し、ターゲット・ノードを決定する。
  4. ターゲット・ノードは行を受け取り、それをローカルに挿入する。
  5. ターゲット・ノードはコーディネーター・エージェントに応答を戻す。
  6. コーディネーターはクライアントに応答を戻す。


区分化データベースにおけるバッファー化挿入

図 2 に示すように、アプリケーションが INSERT BUF オプションを有効にしてバインドされている場合には、イベントの流れが若干異なります。


図 2. 区分化環境におけるバッファー化挿入

  1. データベース・マネージャーは、この表が常駐する各ノードにつき、4KB のページを 1 つオープンします。
  2. データベース・マネージャーは、コーディネーター・エージェントから行を受け取った後、ハッシング・ロジックを適用してターゲット・ノードを決定します。
  3. 行は対応するページに配置されます。
  4. データベース・マネージャーは、制御をアプリケーションに戻します。
  5. この接続が同じ表への行の挿入のみに使用される場合、バッファーは満杯のときか commit または rollback ステートメントの発行時にフラッシュされます。通常、同じ表へ挿入する insert ステートメント以外のステートメント (別の表へ挿入する insert や、表からの delete、表の update など) の発行時には、バッファーはフラッシュされます。

バッファーをフラッシュするステートメントの完全な一覧表については、『DB2 UDB 7.2 アプリケーション開発の手引き』の「区画環境におけるプログラミング上の考慮事項」(6.03MB)を参照してください。

  • ターゲットが受け取るバッファーごとに 1 つのメッセージのみが、ターゲット・ノードからコーディネーター・ノードへ送信されるので、ノード間の通信オーバーヘッドを削減されます。
  • コーディネーター・ノードは、他のノード間で挿入が行われている間に、新規行を受信できます。

バッファー化挿入を活用するには、INSERT BUF オプションを有効にしてアプリケーションをバインドする必要があります。JDBC では、SQL ステートメントは実行時に動的にバインドされます。このため、JDBC に基づいて記述されたコードは、バッファー化挿入を使用できません。しかし、SQLJ ベースのデータベース・コードでこの機能を使用することはできます。



SQLJ とバッファー化挿入 − 例

たとえば、次のように定義された表に行を挿入する Java プログラムを例にとってみましょう。


                
create table testtable (
  id integer not null,
  name char(20) not null,
  age smallint not null,
  address char(74) not null )
  partitioning key (id);
alter table testtable add primary key(id);


id という名前の列は、表の主キーであり区分化キーでもあります。

次の 2 つのクラスを使用して、この表にデータを挿入するコードを実装します。

  • TestTableRow.java。これは表内の 1 行を表します (リスト 1 参照)。

    リスト 1. TestTableRow.java クラス
                            
    // TestTableRow.java
    /**
     * Represents a row of data in TestTable
     */
    public class TestTableRow {
      public int id;
      public String name;
      public short age;
      public String address;
    }
    

リスト 1 では、便宜上、メンバー変数を public に保ちました。

  • TestTableInserter.sqlj。これは表へ 1 行挿入するインターフェースを提供します。
    リスト 2 に示したクラスは、testtable の挿入操作を実装します。

    リスト 2. 挿入操作用の TestTableInserter.sqlj
                            
    // TestTableInserter.sqlj
    import java.sql.*;
    
    /**
     * Implements the method to insert a row into testtable
     */
    public class TestTableInserter {
    
      /**
       * Stores the DefaultContext object used in the insert statement
       */
      protected sqlj.runtime.ref.DefaultContext _defaultContext;
    
      /**
       * Stores the DefaultContext object used in the insert statement
       */
      protected sqlj.runtime.ExecutionContext _executionContext ;
    
      /**
       * Sole Constructor. Sets the protected DefaultContext variable and initializes the
       * ExecutionContext to be used for the insert statement.
       * @param connCtx DefaultContext object used for SQLJ operations
       */
      public TestTableInserter( sqlj.runtime.ref.DefaultContext connCtx) {
        _defaultContext = connCtx;
        // This instance of ExecutionContext will be used in the insert operation
        _executionContext = new sqlj.runtime.ExecutionContext( );
      }
    
      /**
       * Inserts a single row into the testtable.
       * @param row TestTableRow object containing data to be inserted
       * @throws SQLException when database error occurs
       */
      public void insertRow(TestTableRow row) throws SQLException {
        int    id      = row.id;
        String name    = row.name;
        short  age     = row.age;
        String address = row.address;
        #sql [_defaultContext,_executionContext] { insert into testtable values
    	                                         (:id, :name, :age , :address) };
      }
    }
    

TestTableInserter.sqlj に対して SQLJ 変換プログラム (sqllib\bin\sqlj.exe) を実行します。これは SQLJ プログラム中の SQL ステートメントを Java ソース・ステートメントに置き換え、SQLJ ソース・ファイル内の SQL ステートメントに関する情報を含むシリアル化されたプロファイルを生成します。

変換プログラムによって生成されるコードは、付録 A にあります。

デフォルトでは、この java ファイルの作成とは別に、変換プログラムは次のようなステップを実施します。

  1. TestTableInserter.java をコンパイルして 2 つのクラス・ファイル (TestTableInserter.class と TestTableInserter_SJProfileKeys.class) を生成します。
  2. TestTableInserter_SJProfile0.ser を生成します。これには、元のソースに組み込まれた SQL ステートメントに関するプロファイル情報が含まれます。

SQL 処理の概要については、John Cambell 著の技術白書『Meet the Experts』の該当する部分を参照してください。

さて、db2profc コマンドを実行して、生成されたプロファイル上に DB2 SQLJ カスタマイザーをインストールし、ターゲットの DB2 データベース内に DB2 パッケージを作成します。



                
db2profc -user=dbuser -password=dbpwd -url=jdbc:db2:dbname -prepoptions=
"bindfile using TestTableInserter.bnd package using TTblIns insert buf"
TestTableInserter_SJProfile0.ser

注: この insert ステートメントがバッファー化挿入の候補になるのは、db2profc コマンドの prepositions プロパティーの一部として insert buf オプションが指定されているためです。このオプションのデフォルト値の insert def は、バッファー化挿入を無効にします。



RTStatement オブジェクトの再利用による最適化

さて、db2profc コマンドを実行して、生成されたプロファイル上に DB2 SQLJ カスタマイザーをインストールし、ターゲットの DB2 データベース内に DB2 パッケージを作成します。


リスト 3. SQLJ 変換プログラムによって生成されたコード
                
1	{
2	sqlj.runtime.ConnectionContext __sJT_connCtx = _defaultContext;
3	if (__sJT_connCtx == null) sqlj.runtime.error.RuntimeRefErrors.raise_NULL_CONN_CTX();
4	sqlj.runtime.ExecutionContext __sJT_execCtx = _executionContext;
5	if (__sJT_execCtx == null) sqlj.runtime.error.RuntimeRefErrors.raise_NULL_EXEC_CTX();
6	int __sJT_1 = id;
7	String __sJT_2 = name;
8	short __sJT_3 = age;
9	String __sJT_4 = address;
10	synchronized (__sJT_execCtx) {
11	sqlj.runtime.profile.RTStatement __sJT_stmt = __sJT_execCtx.registerStatement
12                     (__sJT_connCtx, TestTableInserter_SJProfileKeys.getKey(0), 0);
13	try
14	{
15	__sJT_stmt.setInt(1, __sJT_1);
16	__sJT_stmt.setString(2, __sJT_2);
17	__sJT_stmt.setShort(3, __sJT_3);
18	__sJT_stmt.setString(4, __sJT_4);
19	__sJT_execCtx.executeUpdate();
20	}
21	finally
22	{
23	__sJT_execCtx.releaseStatement();
24	}
25	}
26	}

リスト 3 では、insertRow 関数を呼び出すたびに、生成されたコードが RTStatement クラスのインスタンスを作成し (行番号 11)、破棄する (行番号 23) ことが明らかです。これはオーバーヘッドです。付録 B の SQLJStmtCachedTestTableInserter クラスに示すとおり、筆者はコードを次のように変更してこのオーバーヘッドを除去しました。

  • RTStatement のインスタンスを保管するために、保護変数 _insertStatement を追加しました。
  • registerStatement への呼び出しは SQLException を発行できるので、「throws SQLException」文節を構成体に追加しました。
  • insertRow メソッド内の registerStatement 呼び出しを TestTableInserter の構成体に移動しました。
  • insertRow メソッドは RTStatement の保護インスタンスを使用するようになっています。新規 RTStatement オブジェクトは、insertRow が呼び出されるたびに作成する代わりに、構成体の中に 1 回だけ作成されるようになり、insertRow 呼び出しに何度でも使用できます。
  • insertRow メソッドにより、SQLException を発行できます。さらに、_insertStatement はこのクラスのインスタンス変数であるため、呼び出しの後で毎回 RTStatement クラスのインスタンスを破棄する必要はありません。したがって、そのコードを除去し、最終的に insertRow メソッド内にブロック化します。
  • ガーベッジ・コレクション中に RTStatement オブジェクトを解放するために、finalize メソッドを追加しました。

ベンチマーク結果

次のシナリオを用いて、バッファー化挿入の使用によるパフォーマンス向上を調査しました。

  • 行の長さがバッファー化挿入に与える影響
  • commit の頻度がバッファー化挿入に与える影響

さまざまなテスト・ケースの実施に、図 3 に示す展開構成が使用されました。


図 3. ベンチマーク構成

すべてのテスト・ケース・シナリオで、クライアント・アプリケーションはテスト・データベースのカタログ・ノードである Node 1 に接続していました。さらに、調査で使用されたテスト・データは、2 つのノード間でほぼ均等に分割されました。

ベンチマークで使用したマシン構成は表 1 に示すとおりです。

Table 1: Machine configurations
System OS CPU Memory Software
Node 1 - CatalogWin NT 4.0 (SP5)Pentium III 647 MHz 196 MBIBM DB2 UDB EEE 7.2
Node 2Win NT 4.0 (SP5)Pentium III 647 MHz196 MBIBM DB2 UDB EEE 7.2
ClientWin 2000 ProfessionalPentium III 800 MHz128 MBIBM DB2 UDB EEE 7.2 Client

行の長さがバッファー化挿入に与える影響の調査には、SQLJStmtCachedTestTableInserter (RTStatement 再利用) と TestTableInserter クラスを使用しました。10000 行を testtable に挿入するには、クライアント・アプリケーションを使用しました。行のサイズは、address 列のデータ・タイプを変更して、0.1 KB 〜 4KB の間で変化させました。commit がバッファー化挿入に与える影響を最小化するために、挿入テスト・プログラムの最後に commit を 1 つ使用しました。テストは、バッファー化挿入が有効のときと無効のときの両ケースで実施しました。プレーンな JDBC コードを使用した挿入パフォーマンスも、さまざまな行の長さに対して測定しました。結果を図 4 に示します。


図 4. 行サイズがバッファー化挿入に与える影響

結果は、バッファー化挿入を使用したときのパフォーマンスの優位性を示しています。行の長さが短い場合、バッファー化挿入を使用した 1 秒あたりの挿入回数は、単純な挿入と比べて何倍にもなりました。行が長くなるにつれ、バッファー化挿入によるパフォーマンスの恩恵は激減します。これは、行が長くなればなるほど、フラッシュされるまでバッファーに保持できる行数が減るためです。

前述のとおり、(他にもいろいろありますが) commit ステートメントを発行すると、バッファー化挿入で使用されるバッファーがフラッシュされます。したがって、commit の頻度が増えると、バッファリングによるパフォーマンスの恩恵もなくなります。図 5 で、以下を使用したときの commit 頻度の影響を比較しています。

付録 D のリストは、両 SQLJ のバリアントテストに使用したテスト・プログラムを示しています。


図 5. commit の頻度がバッファー化挿入に与える影響

結果では、バッファー化挿入を使用するパフォーマンス上のメリットは、commit 頻度が上がるにつれ、また行が長くなるにつれて減ることがわかりました。

両テストは、2 ノード構成上で実施されました。データベース・ノードの数を増やすにつれて、パフォーマンスはほぼ線形に向上することに留意してください。


制限

バッファー化挿入を使用してアプリケーションを設計する場合、この機能の次のような制限について考慮する必要があります。

  • バッファー化挿入は、表への頻繁な挿入を最適化するためにのみ便利なテクニックです。このテクニックを、一連の表に対する挿入、更新、削除が混在する典型的な OLTP ワークロードに使用することはお勧めできません。
  • 行グループの挿入中にエラーが検知されると、そのグループ内のすべての行は取り消されます。行グループは、バッファー化挿入のステートメントを使用して、次の時点から挿入されたすべての行として定義されます。
    • 作業単位の始めから
    • ステートメントが準備されてから (動的の場合)、あるいは
    • バッファー化挿入をクローズまたはフラッシュする別のステートメントが前回実行されてから
  • 非同期という特性のため、バッファー化挿入はアプリケーション・プログラムに影響する特定の動作を示します。特定のエラー状態は挿入の一環としては報告されない場合があり、バッファー化挿入ステートメントをクローズする任意のステートメントに対して報告されることがあります。たとえば、commit ステートメントを発行したときに、-803 (ユニークキー違反) という SQL エラー・コードを受け取ることもあります。
  • 挿入された行は、カーソルを使用した SELECT ステートメントを通して即座に見ることはできません。バッファー化挿入を使用している場合、アプリケーションはカーソルで選択した行に依存すべきではありません。

結論

区分化環境では、バッファー化挿入を使用して、非常に高速な挿入パフォーマンスを実現できます。この機能を Java で利用するには、コードは SQLJ に基づく必要があります。同一の表に大量の挿入を実施するアプリケーションには便利です。行の長さの短い表には、パフォーマンスの恩恵は絶大です。


謝辞

筆者は次の各氏に対して謝意を表します。Infosys 社の Srinivas Thonse 氏には、本記事の初期原稿で完璧なテクニカル・レビューをしていただき、さらには励ましもいただきました。IBM の Cass Squire 氏と Glen Sheffield 氏には、本記事の公開にあたり、いくつかの思慮深いコメントとガイダンスをいただきました。Kathy Zeidenstein 氏には、完璧な編集レビューをしていただきました。


付録A

次のリストは、sqlj 変換プログラムによって生成されたコードです。


                
/*@lineinfo:filename=TestTableInserter*//*@lineinfo:user-code*//*@lineinfo:1^1*/// TestTableInserter.sqlj
import java.sql.*;

/**
 * Implements the method to insert a row into testtable
 */
public class TestTableInserter {

  /**
   * Stores the DefaultContext object used in the insert statement
   */
  protected sqlj.runtime.ref.DefaultContext _defaultContext;

  /**
   * Stores the DefaultContext object used in the insert statement
   */
  protected sqlj.runtime.ExecutionContext _executionContext ;

  /**
   * Sole Constructor. Sets the protected DefaultContext variable and initializes the
   * ExecutionContext to be used for the insert statement.
   * @param connCtx DefaultContext object used for SQLJ operations
   */
  public TestTableInserter( sqlj.runtime.ref.DefaultContext connCtx) {
    _defaultContext = connCtx;
    // This instance of ExecutionContext will be used in the insert operation
    _executionContext = new sqlj.runtime.ExecutionContext( );
  }

  /**
   * Inserts a single row into the testtable.
   * @param row TestTableRow object containing data to be inserted
   * @throws SQLException when database error occurs
   */
  public void insertRow(TestTableRow row) throws SQLException {
    int    id      = row.id;
    String name    = row.name;
    short  age     = row.age;
    String address = row.address;
    /*@lineinfo:generated-code*//*@lineinfo:40^4*/

//  ************************************************************
//  #sql [_defaultContext,_executionContext] { insert into testtable values (:id, :name, :age , :address)  };
//  ************************************************************

{
  sqlj.runtime.ConnectionContext __sJT_connCtx = _defaultContext;
  if (__sJT_connCtx == null) sqlj.runtime.error.RuntimeRefErrors.raise_NULL_CONN_CTX();
  sqlj.runtime.ExecutionContext __sJT_execCtx = _executionContext;
  if (__sJT_execCtx == null) sqlj.runtime.error.RuntimeRefErrors.raise_NULL_EXEC_CTX();
  int __sJT_1 = id;
  String __sJT_2 = name;
  short __sJT_3 = age;
  String __sJT_4 = address;
  synchronized (__sJT_execCtx) {
    sqlj.runtime.profile.RTStatement __sJT_stmt = __sJT_execCtx.registerStatement
	(__sJT_connCtx, TestTableInserter_SJProfileKeys.getKey(0), 0);
    try
    {
      __sJT_stmt.setInt(1, __sJT_1);
      __sJT_stmt.setString(2, __sJT_2);
      __sJT_stmt.setShort(3, __sJT_3);
      __sJT_stmt.setString(4, __sJT_4);
      __sJT_execCtx.executeUpdate();
    }
    finally
    {
      __sJT_execCtx.releaseStatement();
    }
  }
}


//  ************************************************************

/*@lineinfo:user-code*//*@lineinfo:40^106*/
  }
}/*@lineinfo:generated-code*/class TestTableInserter_SJProfileKeys
{
  private static TestTableInserter_SJProfileKeys inst = null;
  public static java.lang.Object getKey(int keyNum)
    throws java.sql.SQLException
  {
    if (inst == null)
    {
      inst = new TestTableInserter_SJProfileKeys();
    }
    return inst.keys[keyNum];
  }
  private final sqlj.runtime.profile.Loader loader = sqlj.runtime.RuntimeContext.getRuntime().getLoaderForClass(getClass());
  private java.lang.Object[] keys;
  private TestTableInserter_SJProfileKeys()
    throws java.sql.SQLException
  {
    keys = new java.lang.Object[1];
    keys[0] = sqlj.runtime.ref.DefaultContext.getProfileKey(loader, "TestTableInserter_SJProfile0");
  }
}


付録B

次のコードは、パフォーマンス調査で使用された、変更済みコードです。


                
/*@lineinfo:filename=SQLJStmtCachedTestTableInserter*//*@lineinfo:user-code*//*@lineinfo:1^1*/// TestTableInserter.sqlj
import java.sql.*;

/**
 * Implements the method to insert a row into testtable
 */
public class SQLJStmtCachedTestTableInserter {

  /**
   * Stores the DefaultContext object used in the insert statement
   */
  protected sqlj.runtime.ref.DefaultContext _defaultContext;

  /**
   * Stores the DefaultContext object used in the insert statement
   */
  protected sqlj.runtime.ExecutionContext _executionContext ;

  /**
   * Stores the registered insert statement
   */
  protected sqlj.runtime.profile.RTStatement _insertStatement ;

  /**
   * Releases the RTStatement object during garbage collection
   * @throws SQLException if releaseStatement call fails
   */
  protected void finalize() throws SQLException {
    _executionContext.releaseStatement();
  }

  /**
   * Sole Constructor. Sets the protected DefaultContext variable and initializes the
   * ExecutionContext to be used for the insert statement.
   * @param connCtx DefaultContext object used for SQLJ operations
   * @throws SQLException if registerStatement call fails
   */
  public SQLJStmtCachedTestTableInserter( sqlj.runtime.ref.DefaultContext connCtx) throws SQLException {
    _defaultContext = connCtx;
    // This instance of ExecutionContext will be used in the insert operation
    _executionContext = new sqlj.runtime.ExecutionContext( );
    _insertStatement = _executionContext.registerStatement(_defaultContext, TestTableInserter_SJProfileKeys.getKey(0), 0);
  }

  /**
   * Inserts a single row into the testtable.
   * @param row TestTableRow object containing data to be inserted
   * @throws SQLException when database error occurs
   */
  public void insertRow(TestTableRow row) throws SQLException {
    int    id      = row.id;
    String name    = row.name;
    short  age     = row.age;
    String address = row.address;
    /*@lineinfo:generated-code*//*@lineinfo:40^4*/

//  ************************************************************
//  #sql [_defaultContext,_executionContext] { insert into testtable values (:id, :name, :age , :address)  };
//  ************************************************************

{
  sqlj.runtime.ConnectionContext __sJT_connCtx = _defaultContext;
  if (__sJT_connCtx == null) sqlj.runtime.error.RuntimeRefErrors.raise_NULL_CONN_CTX();
  sqlj.runtime.ExecutionContext __sJT_execCtx = _executionContext;
  if (__sJT_execCtx == null) sqlj.runtime.error.RuntimeRefErrors.raise_NULL_EXEC_CTX();
  int __sJT_1 = id;
  String __sJT_2 = name;
  short __sJT_3 = age;
  String __sJT_4 = address;
  synchronized (__sJT_execCtx) {
      _insertStatement.setInt(1, __sJT_1);
      _insertStatement.setString(2, __sJT_2);
      _insertStatement.setShort(3, __sJT_3);
      _insertStatement.setString(4, __sJT_4);
      __sJT_execCtx.executeUpdate();
  }
}


//  ************************************************************

/*@lineinfo:user-code*//*@lineinfo:40^106*/
  }
}/*@lineinfo:generated-code*/class TestTableInserter_SJProfileKeys
{
  private static TestTableInserter_SJProfileKeys inst = null;
  public static java.lang.Object getKey(int keyNum)
    throws java.sql.SQLException
  {
    if (inst == null)
    {
      inst = new TestTableInserter_SJProfileKeys();
    }
    return inst.keys[keyNum];
  }
  private final sqlj.runtime.profile.Loader loader = sqlj.runtime.RuntimeContext.getRuntime().getLoaderForClass(getClass());
  private java.lang.Object[] keys;
  private TestTableInserter_SJProfileKeys()
    throws java.sql.SQLException
  {
    keys = new java.lang.Object[1];
    keys[0] = sqlj.runtime.ref.DefaultContext.getProfileKey(loader, "TestTableInserter_SJProfile0");
  }
}



付録C


                
import java.sql.*;
import java.util.*;

class JDBCTableInserterTester
{

	static
	{
		try
		{
			Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	public static void main(String args[]) throws Exception
	{
		String url = "jdbc:db2:testdb";
		Properties prop = new Properties();
		prop.put("user", "user");
		prop.put("password", "pwd");
		Connection con = null;
		int commitFrequency ;
		if (args.length ==0 )
			commitFrequency = 10000;
		else
			commitFrequency = Integer.parseInt(args[0]);
		try
		{
			// connect with user id/password
			con = DriverManager.getConnection(url, prop);
			con.setAutoCommit(false);
		}
		catch (SQLException e)
		{
			System.out.println("Error: could not open connection to database");
			System.err.println(e) ;
			System.exit(1);
		}

		System.out.println("Starting to insert : " + new java.util.Date() ) ;
		PreparedStatement inserter = con.prepareStatement("insert into testtable values(?,?,?,?)");;
		String name = "myname";
		short age = 27;
		char[] arr = new char[74];
		Arrays.fill(arr, 'a');
		String address = new String(arr);
		for ( int id = 0; id < 10000; id++ ) {
			inserter.setInt(1, id);
			inserter.setString(2,name);
			inserter.setShort(3,age);
			inserter.setString(4, address);
			inserter.executeUpdate();
			if ((id + 1) % commitFrequency == 0) con.commit();
		}
		con.commit();
		System.out.println("Finished inserting : " + new java.util.Date() ) ;
	}

}


付録D


                
import java.sql.*;
import java.util.*;
import sqlj.runtime.*;
import sqlj.runtime.ref.*;

class SQLJTableInserterTester
{

	static
	{
		try
		{
			Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	public static void main(String args[]) throws Exception
	{
		String url = "jdbc:db2:testdb";
		Properties prop = new Properties();
		prop.put("user", "user");
		prop.put("password", "pwd");
		int commitFrequency ;
		if (args.length ==0 )
			commitFrequency = 10000;
		else
			commitFrequency = Integer.parseInt(args[0]);

		Connection con = null;
		DefaultContext ctx = null;
		try
		{
			// connect with default id/password
			con = DriverManager.getConnection(url, prop);
			con.setAutoCommit(false);
			ctx = new DefaultContext(con);
		}
		catch (SQLException e)
		{
			System.out.println("Error: could not get a default context");
			System.err.println(e) ;
			System.exit(1);
		}

		System.out.println("Starting to insert : " + new java.util.Date() ) ;
		TestTableRow row = new TestTableRow();
		TestTableInserter inserter = new TestTableInserter(ctx);
		row.name = "myname";
		row.age = 27;
		char[] arr = new char[74];
		Arrays.fill(arr, 'a');
		row.address = new String(arr);
		for ( int id = 0; id < 10000; id++ ) {
			row.id = id;
			inserter.insertRow(row);
			if ( (id + 1) % commitFrequency == 0 ) con.commit();
		}
		con.commit();
		System.out.println("Finished inserting : " + new java.util.Date() ) ;
	}

}
		    



ダウンロード

内容ファイル名サイズダウンロード形式
PDF形式bufferedInsertSource.zip10KBHTTP

ダウンロード形式について


参考文献

著者について

vinu2.jpg

Kishnakumar Pooloth 氏は、Infosys Technologies 社 (http://www.infy.com) のテクニカル・スペシャリスト。オブジェクト・デザイン、コンポーネント・テクノロジー、データベース最適化、および J2EE のエンタープライズ・クラス・アプリケーションの開発の経験を有す。DB2 UDB アプリケーション開発の IBM 認定ソリューション・エキスパートである。インドのカリカット大学から電子通信工学の学位を取得。 メール・アドレス: krishnakumarp@infy.com

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Information Management
ArticleID=323327
ArticleTitle=DB2 UDB EEE 上での Javaを使用したハイパフォーマンス挿入
publish-date=042002
author1-email=
author1-email-cc=

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。