IBM Support

【TF】【IBMZ】【IM】【Db2/z】ユニバーサル表スペースにおいてFETCHとDELETE & INSERTを組み合わせた処理を行う場合の考慮点

Troubleshooting


Problem

Db2 12 for z/OSでは、ユニバーサル表スペース以外のタイプの表スペースは非推奨機能となりました。Db2の機能レベルがV12R1M504以降でBINDされたパッケージからのDDL実行では、これらの表スペースの新規作成は抑止されます(※)。
このことから、既存資源のユニバーサル表スペースへの移行が推奨されますが、従来のタイプの表スペース(単純表スペース、セグメント化表スペース、クラシック区分表スペース)から、ユニバーサル表スペースに変換する際、表スペースのタイプの違いによる影響でアプリケーションの挙動が変わるケースがあることが確認されています。
当テクニカル・フラッシュでは、表スペースのタイプの違いによって起き得る事象について、既知の特定のケースに基づいて解説します。これはDb2のマニュアルに追記されたTip(以下のリンク先の冒頭部分)に該当するものですが、「currently committed data機能」(後述)を使っていなくても発生する事象であることにご注意ください。
※Db2の機能レベルに関する制約などはAPPLCOMPATで制御できるため、APPLCOMPATオプションでV12R1M503以前を指定してBINDしたパッケージを使用すれば、Db2として機能レベルV12R1M504以降であっても、ユニバーサル表スペース以外のタイプの表スペースを作成することは出来ます。ただし、単純表スペースはV9以降で既に新規作成が不可となっています。

Symptom

以下のようなアプリケーション・ロジックを含む処理において、従来タイプの表スペースでは問題なく稼働していたアプリケーションでも、ユニバーサル表スペースに変換した後では、FETCHによる読み込み回数、およびDELETE & INSERTの回数が大幅に増加する等の事象が確認されています。
1. CURSOR OPEN
2. ループ(条件に適合するすべての行について)
 2-1 FETCH
 2-2 DELETE
 2-3 INSERT
3. CURSOR CLOSE
この事象は、1でOPENしたカーソルを2のループ内のFETCHで読み込む際、2-3で挿入した行を、次回(以降)の2-1のFETCHにて読み込んでしまうために起きます。条件によってはループが終わらない可能性もあります。
もともと想定していた件数分は正常に処理されますが、それ以上の処理が行われたかは、DML、つまりFETCH, DELETE, INSERTの実行回数を確認する必要があります。

Cause

この事象はカーソルを使ったFETCHの実行方式次第では全てのタイプの表スペースで起き得えます。実際には、表スペースのタイプの違いによって、発生頻度やループの回数等が変わることがあります。そのため、従来タイプの表スペースではロジック上は起き得るものの他の条件等で問題なく動作していたものが、ユニバーサル表スペースに変換することで事象が表面化する可能性があります。
カーソルFETCHの実行方式の違い
通常、Db2 for z/OSではカーソルによるFETCHの実行は以下の2つの方式のいずれかで処理されます。(Db2のマニュアルのOPENステートメントの記載を参照)
  • OPEN時に適合行を全て読み取った結果表の「一時コピー」を作成し、後続のFETCH要求ではそのコピーに対して処理を行う
  • OPEN時に結果表の「一時コピー」を作成することはぜず、FETCH要求の都度、適合行を見つけて処理を行う
当フラッシュで取り上げている事象は、前者の実行方式では発生しません。後者の実行方式で発生しうるものです。後者においては、カーソルOPEN後、同一コミットスコープ内で新たにINSERTされた行が検索条件に合致するものであった場合、その後に実行されたFETCHの挙動に影響を及ぼすことがあります。
アプリケーションは、上記の実行方式の違いを理解し、いずれの場合でも期待した結果となるようにアプリケーションの処理を実装する必要があります。Db2のマニュアルには、後者の実行方式が選択された場合に、予想しない挙動をする可能性のある事象が例示されています。今回の事象は、後者の実行方式でFETCHを行う際に、カーソルがある位置よりも後ろの領域に行がINSERTされることで発生します。
従来のタイプの表スペースでのDELETE & INSERTの挙動
従来のタイプの表スペースでは、行のDELETEとINSERTを行っても、クラスタリング索引が定義されているキーの値が変わらなければ、INSERTされた行はDELETE前と同じ物理領域や同じRIDが使われる可能性が高いです。そのため、後続のFETCHでカーソル位置が移動した際に、DELETE & INSERTした行が再度適合行として読まれる可能性は低くなります。
このように、ロジック上は"Symptom"で記載した事象が発生しうる可能性はあっても、実際にはDELETE & INSERTの結果、キーの値や行長が変わらない、行長が変わってもページ内に空き領域が確保されている、といった様々な条件によって、結果的にユーザーが想定したとおりの挙動となっていることが多いと考えられます。
ユニバーサル表スペースにおけるDELETE & INSERTの挙動
ユニバーサル表スペースでは、行のDELETEとINSERTを行った際、次に述べるDb2の実装の変更によって、クラスタリング索引が定義されているキーの値が変わらなくても、INSERTされた行はDELETE前とは異なる物理領域に格納されます。
ユニバーサル表スペースでの挙動の変化は、Db2 for z/OS V10から提供された「Currently Committed Data」の機能に関係があります。この機能が有効となっている参照処理は、並行して稼働する処理によってDELETE & INSERTされた行がコミットされるのを待つのではなく、ロック待ちせずに前回コミット済の変更前イメージの行を返す挙動をします。これにより、アプリケーションの並列稼働の向上をサポートします。Db2は、V10以降のユニバーサル表スペースでのみCurrently Committed Dataをサポートします。対象はDELETEおよびINSERTであり、UPDATEについては現時点でも未サポートです。
このCurrently Committed Dataのサポートのため、ユニバーサル表スペースでは行のDELETEの際、物理的にはその行を削除せず、削除されたものとしてフラグを立てる「疑似削除」という実装に変更されました。その結果、未コミットの状態で行のDELETE/INSERTを繰り返し実行すると、既存の行は「擬似削除」状態として物理的に保持され、新たにINSERTされた行はもとの場所とは異なる新たな領域に格納されていきます。疑似削除の行はコミットされるまで「使用領域」として保持され、コミット後に他のアプリケーションから再利用可能となります。
このように、ユニバーサル表スペースでは、同一コミットスコープ内でのDELETE & INSERTでは、INSERTされる行は必ず異なる空き領域に格納されるという挙動になります。「Currently Committed Data」の機能が有効かどうかに関わらず、Db2 V10以降はこの挙動となります
そのため、カーソルOPEN時に適合行のセット(結果表)を確定しないケースでは、INSERTされた行を後続のFETCHで適合行として読み込み、新たなDELETE & INSERT処理を発生させてしまう可能性が高くなります。

Resolving The Problem

ここではDb2のマニュアルでもTipsとして記載されている、UPDATEへの書き換えによる回避案について述べます。
ユニバーサル表スペースでも、UPDATEであれば行を擬似削除とすることはなく、既存の行をそのまま更新します。そのため、DELETE & INSERTをUPDATEに書き換えることにより、ループ内でINSERTされた行をカーソルが移動した際に読み込んでしまうことを回避できます。
なお、可変長行の場合で、UPDATEによって行長が変わってしまうと、元の場所ではなく別の場所に移動することがあります。このような行を「オーバーフロー・レコード」と呼びます。Db2 for z/OSではこのような行を判別する事が可能であるため、行の保管場所が物理的に後方に変わったとしても、同一カーソルのFETCHにてその行を再度読んでしまうことはありません。
したがって、アプリケーション・ロジックは以下のようになります。
1. CURSOR OPEN
2. ループ
 2-1 FETCH
 2-2 UPDATE
3. CURSOR CLOSE
当テクニカル・フラッシュ記載の事象については、このようにDELETE & INSERTではなく、UPDATEとすることで対処可能です。アプリケーション・ロジックやカーソルの定義内容によっては、UPDATEへの書き換えではなく他の手法による回避案が有効となることがあります。

Document Location

Japan

[{"Type":"MASTER","Line of Business":{"code":"LOB10","label":"Data and AI"},"Business Unit":{"code":"BU059","label":"IBM Software w\/o TPS"},"Product":{"code":"SSEPEK","label":"Db2 for z\/OS"},"ARM Category":[{"code":"a8m0z0000000755AAA","label":"Database Objects and Configuration-\u003ETable space"}],"ARM Case Number":"","Platform":[{"code":"PF035","label":"z\/OS"}],"Version":"10.1.0;11.1.0;12.1.0;and future releases"}]

Document Information

Modified date:
08 November 2021

UID

ibm16510422