ルーチン開発に関するパフォーマンスの考慮

クライアント・アプリケーションを拡張する代わりにルーチンを開発することの大きな利点の 1 つは、 パフォーマンスです。

ルーチンの実装のためのアプローチを選択するときには、次のようなパフォーマンス上の影響に配慮してください。

NOT FENCED モード
NOT FENCED ルーチンは、データベース・マネージャーと同じプロセス中で稼働します。 一般的に、ルーチンを NOT FENCED で実行したほうが、FENCED モードで実行する場合よりもパフォーマンスが改良されます。FENCED ルーチンは、エンジンのアドレス・スペース外部の特別なデータベース・マネージャー・プロセスで実行されるからです。

ルーチンを NOT FENCED モードで実行するとルーチンのパフォーマンスの向上は期待できますが、ユーザー・コードによってデータベースやデータベース制御構造が意図せずにまたは故意に破壊される可能性があります。 NOT FENCED ルーチンを使用してよいのは、パフォーマンス上の利点を最大化する必要がある場合と、ルーチンが安全であると判断した場合です。 C/C++ ルーチンを NOT FENCED として登録する場合のリスクの評価とその緩和に関する詳細は、『ルーチンのセキュリティーに関する考慮事項』の項を参照してください。 データベース・マネージャーのプロセスで実行するにはルーチンが十分安全でない場合、ルーチンの登録時に FENCED 節を使用します。 安全でない可能性があるコードの作成および実行を制限するために、 データベース・マネージャーは、ユーザーが NOT FENCED ルーチンを作成するときに、特殊な特権 CREATE_NOT_FENCED_ROUTINE を要求します。

NOT FENCED ルーチンの実行中に異常終了が発生する場合、ルーチンが NO SQL として登録されていると、データベース・マネージャーは適切なリカバリーを試行します。 しかし、NO SQL として定義されていないルーチンの場合、データベース・マネージャーは失敗します。

ルーチンが GRAPHIC または DBCLOB データを使用する場合は、NOT FENCED ルーチンを WCHARTYPE NOCONVERT オプションでプリコンパイルする必要があります。

FENCED THREADSAFE モード
FENCED THREADSAFE ルーチンは、他のルーチンと同じプロセスで稼働します。 Java™ ルーチン以外のルーチンは 1 つのプロセスを共有し、Java ルーチンは別のプロセスを共有します。 Java ルーチン・プロセスを他のルーチン・プロセスから分離することで、他の言語で作成されたエラーが発生しやすい可能性のあるルーチンから Java ルーチンを保護します。 また、Java ルーチンのプロセスには JVM が含まれています。これは、メモリー・コストが高くなり、他のルーチン・タイプでは使用されません。 FENCED THREADSAFE ルーチンの複数の呼び出しではリソースを共有するため、それぞれが独自の専用プロセスで実行する FENCED NOT THREADSAFE ルーチンよりもシステムのオーバーヘッドが減ります。

ご使用のルーチンが他のルーチンと同じプロセスで実行しても安全な場合、それを登録する際に THREADSAFE 節を使用してください。 NOT FENCED ルーチンと同様に、C/C++ ルーチンを FENCED THREADSAFE として登録するリスクの評価およびその軽減の詳細については、『ルーチンのセキュリティーに関する考慮事項』のトピックを参照してください。

FENCED THREADSAFE ルーチンが異常終了した場合、このルーチンを実行していたスレッドだけが終了します。 プロセス内のその他のルーチンは実行を続けます。 ただし、このスレッドが異常終了する原因となった障害によって、 プロセス中の他のルーチン・スレッドが悪影響を受けて、 トラップ、ハング、またはデータ損傷を起こす可能性があります。 あるスレッドが異常終了した後は、そのプロセスは新規のルーチンの呼び出しに使用されません。 すべてのアクティブ・ユーザーがこのプロセスでジョブを完了すると、それは終了されます。

Java ルーチンを登録すると、特に指定しない限り、THREADSAFE と見なされます。 その他の LANGUAGE タイプはすべて、デフォルトで NOT THREADSAFE です。 LANGUAGE OLE および OLE DB を使用するルーチンは THREADSAFE として指定できません。

NOT FENCED ルーチンは THREADSAFE でなければなりません。 ルーチンを NOT FENCED NOT THREADSAFE として登録することはできません (SQLCODE -104)。

SQL を実行しないユーザー定義関数は、NO SQL として登録することをお勧めします。 FENCED NO SQL ルーチンを呼び出す場合は、データベース・マネージャーのパフォーマンスが向上します。

UNIX のユーザーは、 db2fmp (Java) または db2fmp (C)を探すことによって、Java および C THREADSAFE プロセスを確認できます。

FENCED NOT THREADSAFE モード
FENCED NOT THREADSAFE ルーチンはそれぞれ、独自の専用プロセスで実行します。 多数のルーチンを実行している場合、このことはデータベース・システムのパフォーマンスに悪影響を及ぼす可能性があります。 ルーチンが他のルーチンと同じプロセスで実行できるほど安全でない場合は、ルーチンを登録する際に NOT THREADSAFE 節を使用してください。

UNIX では、NOT THREADSAFE プロセスは、 db2fmp (pid) ( pid は fenced モード・プロセスを使用するエージェントのプロセス ID) または db2fmp (idle) (プールされた NOT THREADSAFE db2fmpの場合) として表示されます。

SQL を実行しないユーザー定義関数は、NO SQL として登録することをお勧めします。 FENCED NOT THREADSAFE NO SQL ルーチンを呼び出す場合は、データベース・マネージャーのパフォーマンスが向上します。

Java ルーチン
メモリー所要量が大きい Java ルーチンを実行する予定の場合は、Java ルーチンを FENCED NOT THREADSAFE として登録できます。 FENCED THREADSAFE Java ルーチン呼び出しの場合、データベース・マネージャーは、ルーチンを実行するのに十分な大きさの Java ヒープを持つスレッド化された Java fenced モード・プロセスを選択しようとします。 独自のプロセスで大きなヒープ・コンシューマーを分離しないと、マルチスレッド化された Java db2fmp プロセスで Java ヒープ不足エラーが発生する可能性があります。 Java ルーチンがこのカテゴリーに該当しない場合、FENCED ルーチンは、少数の JVM を共有できるスレッド・セーフ・モードでより適切に実行されます。

NOT FENCED Java ルーチンは現在サポートされていません。 NOT FENCED として定義される JAVA ルーチンは、FENCED THREADSAFE Java ルーチンとして扱われます。

C/C++ ルーチン
C または C++ ルーチンは通常、Java ルーチンよりも高速ですが、エラー、メモリー破損、および異常終了の可能性が高くなります。 というわけで、メモリー操作を実行する機能のために、 THREADSAFE または NOT FENCED モードの登録では C または C++ ルーチンはリスクの高い候補となります。 そのようなリスクを軽減するには、 セキュア・ルーチンのためのプログラミングの実践方法を順守 (『ルーチンのセキュリティーに関する考慮事項』の項を参照) して、 ルーチンを徹底的にテストします。
SQL ルーチン
SQL ルーチン、特に SQL プロシージャーは、一般に Java ルーチンよりも高速で、通常は C ルーチンと同等のパフォーマンスを共有します。 SQL ルーチンは常に NOT FENCED モードで稼働するので、 外部ルーチンよりもパフォーマンス上の利点はさらに大きくなります。 複雑なロジックを組み込んだ UDF は、一般的に、SQL で作成するより C で作成するほうが実行速度が上がります。 ロジックが単純な場合、SQL UDF は外部 UDF と同程度です。
スクラッチパッド
スクラッチパッドとは、UDF およびメソッドへの割り当てが可能なメモリー・ブロックのことです。 スクラッチパッドが適用されるのは、SQL ステートメント内のルーチンへの個々の参照に対してのみです。 ステートメント内のルーチンに対して複数の参照がある場合、 どの参照もそれ独自のスクラッチパッドをもつことになります。 スクラッチパッドを使用すれば、 UDF またはメソッドは次の呼び出し時までその状態を保持しておくことができます。

複雑な初期化を伴う UDF およびメソッドでは、スクラッチパッドを使用すると、最初の呼び出しで必要であったすべての値を保管しておいて、 以後のすべての呼び出しでそれを使用することができます。 他の UDF やメソッドのロジックでも、 呼び出しと呼び出しの間で中間値の保管が必要になる場合があります。

CHAR パラメーターにとって代わる VARCHAR パラメーターの使用
ルーチン定義で CHAR パラメーターの代わりに VARCHAR パラメーターを使用すれば、 ルーチンのパフォーマンスを向上させることができます。 CHAR データ・タイプではなく VARCHAR データ・タイプを使用すると、パラメーターの引き渡しの前にデータベース・マネージャーによってパラメーターにスペースが埋め込まれなくなります。これで、ネットワークを経由したパラメーターの転送に要する時間が短縮されます。

例えば、クライアント・アプリケーションが CHAR(200) パラメーターを予期するルーチンにストリング「A SHORT STRING」を渡す場合、 データベース・マネージャーはパラメーターに 186 個のスペースを埋め込み、 ストリングを NULL で終了してから、200 文字のストリングと NULL 終止符全体をネットワーク経由でルーチンに送信する必要があります。

それと比べて、VARCHAR(200) パラメーターを予期するルーチンに同じストリング "A SHORT STRING" を渡すと、データベース・マネージャーは単に 14 文字ストリングと NULL 終止符をネットワーク経由で渡します。