ロックの使用により改善される実行
Db2 は、さまざまなデータ・オブジェクトに対してロックを使用します。
ロックは、行、ページ、表、表スペース・セグメント、表スペース・パーティション、表スペース全体、およびデータベースに対して使用できます。 アプリケーションがロックを獲得すると、アプリケーションは 保持
または 所有
ロックを獲得します。
Db2 ロック モードを使用して、あるロックが別のロックと互換性があるかどうかを判断します。 一部のロック・モードは、他のすべてのユーザーを排除しません。 例えば、アプリケーション処理 A が、処理 B もアクセスしようとしている表スペースにロックを保持しているとします。 Db2 プロセスBに代わって、特定のモードのロックを要求します。 処理 A のロックのモードが、処理 B が要求するロックを許可する場合、これらの 2 つのロックのモードは互換性があると言われます。 しかし、2 つのロックに互換性がない場合、処理 B は先に進むことができません。 処理 B は、処理 A がロックを解放し、他のすべての互換性のない既存のロックが解放されるのを待機する必要があります。
以下のロック・モードは異なる程度の保護を行います。
- Sロック(共用)
- ロック所有者および並行して実行しているどの処理も、 ロックされたページと行を読み取ることができますが、変更はできません。 並行して実行している処理は、ページまたは行に対する S ロックまたは U ロックを獲得するか、あるいはページ・ロックまたは行ロックを獲得せずにデータを読み取ることができます。 Uロックは、1つまたは複数のSロックと同時に1つだけ取得できます。
- U ロック (更新)
- ロック所有者は、ロックされたページまたは行を読み取ることはできますが、変更はできません。 並行して実行している処理は、S ロックを獲得するか、あるいはページ・ロックまたは行ロックを獲得せずにデータを読み取ることができますが、いずれの処理も U ロックを獲得でません。
U ロックは、ロック所有者がページまたは行を読み取って、そのデータを変更すべきかどうかを判断するときに起こるデッドロックの可能性を減少させます。 ロック所有者は、まず U ロックで開始しておいて、ページまたは行を変更する時点で U ロックを X ロックにプロモートすることができます。
- Xロック(排他)
- ロック所有者は、そのロックされたページまたは行を読み取ることも、変更することもできます。 並行的に実行している処理は、ページ上あるいは行上で S、U、または X ロックを獲得できません。 ただし、並行的に実行している処理 (CURRENTDATA(NO) または ISOLATION(UR) バインド・オプションでバインドされている、または EVALUNC サブシステム・パラメーターに YES を指定して実行される処理など) は、ページまたは行ロックを獲得せずにデータを読み取ることができます。
2 つのモードのページ・ロックまたは行ロックに互換性があるかどうかを、以下に示します。 パーティションまたは表スペースはページ・ロックと行ロックの両方を使用することはできないため、ページ・ロックと行ロックの間で互換性の問題が生じることはありません。
| ロック・モード | 共用 (S ロック) | 更新 (U ロック) | 排他 (X ロック) |
|---|---|---|---|
| 共用 (S ロック) | はい | はい | いいえ |
| 更新 (U ロック) | はい | いいえ | いいえ |
| 排他 (X ロック) | いいえ | いいえ | いいえ |
共用ロック、更新ロック、および排他ロックは、行またはページのロックに適用されます。 これらのことが適用されるのは、表がセグメント化表スペース内にある場合の、表スペースまたはその表に対する意図的ロックを獲得するアプリケーション処理に対してだけです。
あるページまたは行がロックされると、そのページが入った表、パーティション、または表スペースもロックされます。 この意図的ロックでは、アプリケーション処理がそのデータにアクセスするために保有しているプランを示します。 その場合、表、パーティション、または表スペースに対するロックのモードは、意図的モード のいずれかになります。意図的モードは、IS (意図的共有)、IX (意図的排他)、または SIX (意図的排他の共有) です。
表スペース・ロックの場合の互換性は、ページ・ロックおよび行ロックと比べて若干複雑です。
ロックは、Db2 環境で並行性を維持するために重要です。 しかし、ロックは、一時停止、タイムアウト、デッドロックなど、 Db2 のパフォーマンスを低下させるいくつかの種類の競合状況を引き起こす可能性があります。
- 中断
- あるアプリケーションが、すでに他のアプリケーションプロセスによって保持されており、共有できないロックを要求した場合、そのアプリケーションは中断状態になります。 延期された処理は、一時的に実行を停止します。 延期された処理は、競合するロックを保持するすべての処理がロックを解放するとき、またはロックを要求している処理がタイムアウトまたはデッドロックになり、エラー条件の扱いを開始するときに、再開されます。
- Timeout
- アプリケーションプロセスがタイムアウトに遭遇するのは、設定された時間間隔を超えるサスペンションにより終了した場合です。 Db2 プロセスを終了し、メッセージを発行し、エラーコードを返します。 コミット操作とロールバック操作はタイムアウトにはなりません。 ただし、STOP DATABASEコマンドがタイムアウトする場合があります。その場合、 Db2 がコンソールにメッセージを送信します。 このような状況が発生した場合、 Db2 はSTOP DATABASEコマンドを最大15回再試行します。
- デッドロック
- 2つ以上のアプリケーションプロセスが、他のプロセスが必要としているリソースに対してそれぞれロックを保持しており、そのロックがなければ処理を進めることができない場合、デッドロックが発生します。 Db2 は、あらかじめ設定された時間間隔の後、プロセスのうちの1つの現在の作業単位をロールバックしたり、プロセスに終了を要求したりすることができます。 どのプロセスをロールバックまたは終了させるかを決定する際、 Db2 はデッドロックに関与しているプロセスの多くの特性を評価し、終了させた場合に他のプロセスへの影響が最も少ないプロセスを選択します。 Db2 は、ロールバックまたは終了するプロセスを選択することでロックを解放し、残りのプロセスを継続させます。
いくつかのロック問題が発生する可能性はありますが、システムとアプリケーションのロック問題を回避することができます。
以下のシナリオでは、ロックの重要性が示されています。
シナリオ: 更新されたデータが失われるのを防止する
2人のユーザー、キャシーとフランクは、同じ Db2 テーブルにアクセスしようとしています。 この場合に、以下のことが発生します。
- Kathy は、データ値 100 をホスト変数に読み取ります。
- Frank は、同じ列値をホスト変数に読み取ります。
- キャシーはホスト変数の値に10を加え、新しい値である110を Db2 テーブルの列に保存します。
- Frankはホスト変数の値に20を加え、新しい値である120を Db2 テーブルの列に保存します。
このシナリオではロックを使用していません。 このシナリオでは、列内の更新対象値は、どのユーザーが最初にこのデータをコミットするかによって異なります。 Kathy が最初にコミットすると、更新された列値は 120 であり、Kathy の更新内容は失われます。 Frank が最初にコミットすると、更新された列値は 110 であり、Frank の更新内容は失われます。
ロックを行うとこのシナリオは変わります。 以下の処理では、更新可能カーソルを使用するものと仮定します。 この場合に、以下のことが発生します。
- Kathy は、列値 100 を読み取り、ホスト変数に入れます。この場合、その値を更新する意図を示して読み取ります。 Db2 その後、キャシーに更新ロックを付与します。
- Frank は、同じ列値を読み取り、ホスト変数に入れます。この場合、その値を更新する意図を示して読み取ります。 上の表の互換性マトリクスによると、 Db2 は、列値100を含む Db2 オブジェクトについて、Frankに更新ロック(Uロック)を許可しません。 このため、Frank は Kathy がこのロックを解放するまで、この列値の読み取りを待つ必要があります。
- キャシーはホスト変数の値に10を加え、新しい値である110を Db2 テーブルの列に保存したいと考えています。 この時点で、 Db2 は、列の値を含む Db2 オブジェクト上のUロックを排他ロック(Xロック)に変更します。
- Kathy は変更内容をコミットします。 Db2 次に、列の値を含む オブジェクトのXロックを解除します。 Db2 次に、 Db2 は同じオブジェクトについて、フランクにUロックを付与します(フランクがアクセスを待っている間にタイムアウトしていない場合)。 Frank が指定したホスト変数には、これにより 110 の更新された値が入ることになります。
- Frank はこのホスト変数値に 20 を加算して新しい値 130 を表の列に格納する必要があります。 Db2 列の値を含む オブジェクトのUロックをXロックに変更します。 Db2
- Frank は変更内容をコミットします。 Db2 次に、列の値を含む オブジェクトのXロックを解除します。 Db2
もしこのシナリオに更新可能なカーソルが含まれていなかった場合、 Db2 はステップ1でUロックの代わりにSロック(共有ロック)をキャシーに付与します。 Db2 また、ステップ2でフランクにSロックを付与する。 Kathy と Frank の両方が列の値を更新しようとすると、デッドロックが発生します。 デッドロックが発生した場合、 Db2 はキャシーの作業またはフランクの作業をロールバックするかを決定します。 ロールバックは、 Db2 が個々のアプリケーションプロセスが試みた変更を元に戻す際に発生します。 Db2 がキャシーの変更をロールバックした場合、キャシーはロックを解除し、フランクはその後、処理を完了することができます。 逆に、 Db2 がフランクの変更をロールバックした場合、フランクはロックを解除し、キャシーは処理を完了することができます。
アプリケーション・プログラムでデッドロック状態の発生を最小化することができます。このためには、DECLARE CURSOR ステートメントにある FOR UPDATE OF 文節を使用します。 このプログラムは、データ・オブジェクトに対する他のすべての U ロックまたは X ロックが解放されるまでは、実際には U ロックを獲得しません。
シナリオ: 非コミットデータに対する読み取りアクセスの防止
2人のユーザー、キャシーとフランクは、同じ Db2 テーブルにアクセスしようとしています。
- キャシーは、 Db2 テーブルの列の値を100から0に更新します。
- Frank は、更新された値 0 を読み取って、その値に基づいてプログラム決定を行います。
- キャシーは処理をキャンセルし、 Db2 テーブルの列の値を0から100に戻します。
このシナリオではロックが含まれていません。 このシナリオでは、Frank は間違ったプログラム決定を行うことを示しています。 その結果、データベースにあるビジネス・データが不正確になる可能性があります。
このシナリオにロックが含まれれば、以下のようになります。
- Kathy は、表の列の中の値 100 を 0 に更新しようとします。 Db2 更新が必要なカラム値を含む オブジェクトに対して、キャシーにXロックを付与します。 Db2
- Frank は更新される列を読み取ろうとして、それによってその値に基づいてプログラム決定を行うことができます。 Db2 Frankが更新された列の値0を読み取ることができません。 Frank は、現在 X ロックを持っている Db2 オブジェクトに対して S ロックを獲得しようとします。 Frank は、Kathy がその処理をコミットまたはロールバックするのを待つ必要があります。
- キャシーは処理を取り消し、 Db2 テーブルの列の値0を元の値100に戻します。 Db2 データに実際に変更を加え、キャシーのXロックを解除します。 Db2 次に、列の値を含む オブジェクトに対して、フランクにSロックを付与します。 Db2 次に、Frank は値 100 を読み取ります。
シナリオにロックが含まれると、Frank は正しいデータを読み取り、それによって正しいプログラム決定を行うことができます。 その結果、データベースにあるビジネス・データは正確になります。
シナリオ: 作業単位内にある複数の読み取りの間に発生する更新の防止
このシナリオでは、Kathy は同じデータを 2 回読み取る必要があります。 この 2 回の読み取りの間では、他のプログラムまたは他ユーザーはそのデータを変更できません。
Kathy は以下の SQL ステートメントを使用すると仮定します。
SELECT * FROM EMP
WHERE SALARY>
(SELECT AVG(SALARY) FROM EMP);この SQL ステートメントでは、EMP 表を 2 回読み取ります。
- このステートメントでは、この表の全行の SALARY 列にある値の平均値を計算します。
- このステートメントでは、SALARY 列で平均値を超える値を持ったすべての行を、EMP 表の中で見つけます。
Kathy がこの 2 つの読み取り処理の間でこのデータにロックを掛けなければ、別のユーザーが、この 2 つの読み取り処理の間に EMP 表を更新することができます。 この更新により、Kathy に対して間違った結果をもたらす可能性があります。
キャシーは、2つの読み取りプロセス間の間にテーブルへの変更が発生しないように、 Db2 ロックを使用することができます。 Kathy は以下の選択肢から選ぶことができます。
- パッケージまたはプランの分離レベルの反復可能読み取り (RR)の使用、または SQL SELECT ステートメント内の WITH RR 文節の使用。
- 以下のステートメントを使用して、共用モードまたは排他モードで表をロック。
- LOCK TABLE EMP IN SHARE MODE
- LOCK TABLE EMP IN EXCLUSIVE MODE