並行性に関するプログラミング
アクセスされるデータの保全性を保護しつつ、他のプロセスが同じデータにアクセスすることを長時間にわたって妨げないように、アプリケーション・プログラムを設計できます。
このタスクについて
DB2® が並行性を制御する基本的な方法の 1 つは、作業単位に対してロックを使用することです。 ある作業単位が完了すると、その作業単位が暗黙的に獲得したロックはすべて解放されて、 新しい作業単位を開始できます。 ある作業単位がプログラムで使用する処理時間の長さは、DB2 が、ロックされたそのデータに 他のユーザーがアクセスできなくする時間の長さに影響します。 複数のプログラムが同じデータを並行して使おうとすると、各プログラムの作業単位に要する時間を極力短くして、プログラム間の干渉を最小限に抑える必要があります。
手順
- アプリケーションが同じ順序でデータにアクセスするようにプログラムします。 2 つのアプリケーションが表の同じ行に同じ順序でアクセスする場合、1 つのアプリケーションはもう 1 つのアプリケーションを待機する必要が生じますが、デッドロックは発生しません。そのため、異なるアプリケーションが同じ順序で行にアクセスし、同じ順序で表にアクセスするようにプログラムすることが推奨されています。
- コミットすることが現実的である場合は、できるだけ早く作業をコミットしてください。それにより、読み取り専用アプリケーションであっても、不要なロック競合が回避されます。
長時間走行でリカバリー単位 (UR) が長くなる場合に頻繁にコミット・ポイントを設定すると 、CPU 使用率およびログ書き込み入出力回数が増加する可能性はありますが、次のような利点があります。
- ロック競合の削減 (特にデータ共用環境の場合)
- ロック回避の効率の向上 (特にデータ共用環境の場合)
- システム障害後における DB2 システム再始動の経過時間の削減
- アプリケーション障害発生後、またはアプリケーションによる明示的ロールバック要求後、 リカバリー単位をロールバックするための経過時間削減
- オンライン REORG などのユーティリティーが割り込む機会の増加
頻繁にコミットしないアプリケーションを特定するために、URCHKTH サブシステム・パラメーターまたは URLGWTH サブシステム・パラメーターの使用を検討してください。URCHKTH は、UR がコミットを発行せずにあまりにも多くのチェックポイントが発生した場合にその状況を特定します。これは、システム・アクティビティー全体をモニターするのに役立ちます。URLGWTH は、コミット・ポイントからコミット・ポイントまでの間にあまりにも多くのログ・レコードを書き込んでいる可能性のあるアプリケーションを検出できます。このようなアプリケーションは、重要な表のリカバリーに時間がかかる状態を潜在的に作り出しています。
あるアプリケーションは通常操作の条件下では使用するシステムにおけるコミット頻度の基準に順応して いたとしても、システムのワークロードの変動に基づいてバリエーションが生じる可能性があります。 例えば、システム負荷が軽い状態では、優先順位の低いアプリケーションがコミットを頻繁に発行して いたとしても構わないでしょう。 しかし、システム負荷が重い状態では、このアプリケーションによる CPU 使用が優先された場合には、 その結果としてこのアプリケーションが URCHKTH サブシステム・パラメーターによって設定された規則に違反する 可能性があります。この理由により、単に実行された SQL 処理の量を基にするのではなく、 最後のコミットからの経過時間を基にしてコミットを発行する論理をアプリケーションに 追加してください。さらに、読み取り専用の実行時間の長い作業単位では コミット・ポイントを頻繁に設定するようにして、ロックによる競合を低減し、オンライン REORG などの ユーティリティーがデータにアクセスできる機会を提供してください。
頻繁にコミットすることが重要なのは、ログされていないオブジェクトでも、ログされているオブジェクトでも同じです。 例えば、作業が NOT LOGGED オプションを指定して定義された表スペース上で行われる場合も、必ず作業を頻繁にコミットしてください。特定のトランザクションが、ログされていない表スペースにある表のみを変更する場合でも、リカバリー単位は更新の実行前に引き続き設定されます。 取り消し処理では、適用対象の取り消しログ・レコードを探して逆方向にログを読み続けます。このことは、このリカバリー単位がログに記録されているので、リカバリー単位の先頭を検出するまで続きます。したがって、このようなトランザクションは頻繁にコミットして、取り消し処理がログを逆方向にたどって、リカバリー単位の先頭を見つけ出すまでの長さを限定する必要があります。
- アプリケーション・プログラムにロジックを組み込んで、デッドロックまたはタイムアウト後に競合状況からの回復を、援助を受けずに再試行します。 このような方法では、運用担当者の援助を求めなくても
当該の状況からリカバリーできる可能性があります。以下の方法を使用して、タイムアウトまたはデッドロックのいずれが発生したかを判別できます。
- SQLCA の SQLERRD(3) フィールド
- GET DIAGNOSTICS ステートメント
- ほとんどのアプリケーションは、ISOLATION(CS) および CURRENTDATA(NO) オプションを指定してバインドします。 これらのオプションは、DB2 によって、ロックを早期に解除し、多くのロックを回避できるようにします。 一般的には、ISOLATION(CS) を使用すると、DB2 は取得済みのロックをできるだけ早く解放できるようになります。CURRENTDATA(NO) は、通常、DB2 が獲得するロック数を最小限に抑え、ロック回避 の効率を向上させることができます。 ISOLATION(CS) および CURRENTDATA(NO) を使用する場合は、SKIPUNCI サブシステム・パラメーターの値を YES にして使用し、コミットされていない挿入の結果を読み取りプログラムが待たないようにします。
- ISOLATION(CS) および CURRENTDATA(NO) を使用しない場合は、優先順位の低い順に、以下のバインド・オプションを使用します。
- ISOLATION(CS) および CURRENTDATA(YES)。これは、アプリケーションに戻されるデータが、 次の FETCH 操作までは変更されてはならない場合。
- ISOLATION(RS)。これは、アプリケーションに戻されるデータが、 アプリケーションがコミットまたはロールバックするまで変更されてはならない場合。ただし、他のアプリケーション処理が追加行を挿入するかどうかには留意しません。
- ISOLATION(RR)。これは、照会の結果として評価されるデータが、 アプリケーションがコミットまたはロールバックするまで変更されてはならない場合。この場合には、新規行を応答セットに挿入することはできません。
- ISOLATION(UR) は慎重に使用する。 リソース・リカバリー・サービス接続機能 UR 分離は、行やページに対するロックを獲得することはほとんどありません。
この
分離機能は高速で、競合はほとんど生じませんが、
コミットされていないデータを読み取ります。アプリケーションおよびエンド・ユーザーが、
生じる可能性がある論理的な矛盾を受け入れることができない場合には、それを使用しないで
ください。
アプリケーションで非コミット・データの読み取りよりも、データの除外を優先する場合は、代わりに SKIP LOCKED DATA 文節の使用を検討してください。
- シーケンス・オブジェクトを使用して固有シーケンス番号を生成する。 固有シーケンス番号を生成する方法の 1 つに、ID 列を使用する方法があります。
ただし、ID 列は、1 つの 表のうちの 1 つの列としてその表に関連付けられ、結び付けられ、1 つの表には 1 つの ID 列しか持てません。 ご使用のアプリケーションは、多数の表を通した 1 つのシーケンスの固有番号、または各表ごとの 複数のシーケンスを使用する必要が生じる場合があります。 ユーザー定義のオブジェクトとして、シーケンスは、アプリケーションが DB2 に固有の数字キー値を生成させ、複数の行および表全体に渡ってキーを調整する方法を提供します。
シーケンスを使用するとロック競合問題を回避できます。このロック競合問題が 発生する可能性があるのは、アプリケーションがその独自のシーケンスをインプリメント時に、 各トランザクションが増分する必要のあるシーケンス番号の入った 1 行だけの表を作成した結果 です。DB2 のシーケンスを使用すると、多くのユーザーは、待たずに、シーケンスを並行的にアクセスおよび増分できます。DB2 は、シーケンスを増分したトランザクションがコミットするのを待たずに、別のトランザクションにさらにシーケンスを増分できるようにします。
- 作業単位が長くなる可能性がある複数行操作 (数行の挿入、位置付け更新、および位置付け削除など) の検査を行う。 これは、ほかのユーザーがデータにアクセスする際の並行性に 影響する可能性があります。 ホスト変数配列のサイズを調整し、挿入、更新の間のコミット、 およびロック・エスカレーションの回避によって、競合を最小限に抑えることができます。
- グローバル・トランザクションを使用します。それにより、DB2 と他のトランザクション・マネージャーが、単一トランザクションに関係するようにして、それにより同一ロックを共用し、同一データにアクセスするようにします。 リソース・リカバリー・サービス
接続機能 (RRSAF) は、リソース・リカバリー・サービス (RRS) という z/OS® コンポーネントに依存します。RRS は、z/OS 製品間の 2 フェーズ・コミット操作の整合を行う
システム全体にわたるサービスを備えています。
RRS の下で実行される RRSAF アプリケーションおよび IMS™ トランザクションでは、
多くの DB2 エージェントを単一のグローバル・トランザクションにグループ化できます。
グローバル・トランザクションを使用して、 複数の DB2 エージェントを単一のグローバル・トランザクションに参加させることができ、 したがって、同じロックを共用することや、同じデータをアクセスすることができます。1 つのグローバル・トランザクションに含まれる 2 つのエージェントが 1 つの作業単位内で同じ DB2 オブジェクトをアクセスする場合、 それらのエージェントが互いにデッドロックを起こしたり、タイムアウトすることはありません。これには、以下の制約事項があります。
- 並列シスプレックス®は、グローバル・トランザクションではサポートされません。
- グローバル・トランザクションの「分岐」のそれぞれがロックを共用するので、 トランザクションの 1 つの分岐で発行したコミットされていない更新は、 そのトランザクションの他の分岐からは認識できます。
- クレーム / ドレーンは、グローバル・トランザクションの分岐にまたがってはサポートされません。 これは、同じグローバル・トランザクションの別々の分岐 から CREATE、DROP、ALTER、GRANT、または REVOKE を発行しようとすると、 デッドロックまたはタイムアウトになる可能性があることを意味します。
- LOCK TABLE によって、 グローバル・トランザクションの分岐間でデッドロックまたはタイムアウトが発生する場合があります。
- オプティミスティック並行性制御を使用する。 オプティミスティック並行性制御 は、並行データ・アクセスでのデータベース・ロッキングに対して、さらに高速でスケーラブルなロッキングを行う代替方法です。これによって、特定のリソースを他のトランザクションが使用できなくなる時間が最小になります。
アプリケーションが、オプティミスティック並行性制御を使用する場合、 ロックは、読み取り操作の直前に取得され、即時に解放されます。 更新ロックは、更新操作の直前に取得され、 そのトランザクションの終了まで保持されます。 オプティミスティック並行性制御は、RID および行変更トークンを使用して、 最後の読み取り操作以降に、別のトランザクションによってデータが変更されたかどうかをテストします。
DB2 は、いつ行が変更されたかを判別できるため、データ保全性を確保しながら、ロックを保持する時間を限定できます。 オプティミスティック並行性制御を使用すると、DB2 は、読み取り操作の直後に行ロックまたはページ・ロックを解放します。DB2 は、各 FETCH の後に行ロックも解除し、新しい行へのロックは位置付け UPDATE または DELETE の場合のみに行い、データ保全性を保証します。
オプティミスティック並行性制御をインプリメントするには、行変更タイム・スタンプ列を、CREATE TABLE ステートメントまたは ALTER TABLE ステートメントで設定する必要があります。この列は、以下のいずれかの NULL 特性で定義する必要があります。
- NOT NULL GENERATED ALWAYS FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP
- NOT NULL GENERATED BY DEFAULT FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP
行変更タイム・スタンプ列を設定すると、この列の内容は DB2 が保守します。 更新を行う時点での条件としてこの変更トークンを使用する場合、 WHERE 文節でこの列に適切な述部を指定できます。