3.4.7 コミットしていない削除データの排他制御
通常,インデクスキーを削除すると,削除トランザクションがコミットする前に,そのインデクスキーはデータベースから削除されます。そのため,削除トランザクションがロールバックした場合,インデクスキーの内容は回復しますが,同時実行中のほかの検索トランザクションからは検索対象外となります。検索対象外となる削除インデクスキーの例を次の図に示します。
|
- [説明]
-
削除トランザクションがコミットする前に,キーAはデータベースから削除されます。そのため,検索トランザクション1はキーAを読み飛ばし,キーBを検索に使用します。その後ロールバックが発生しなかった場合は,検索トランザクション2は検索トランザクション1と同様に,検索にキーBを使用します。
一方,ロールバックが発生してキーAの内容が回復した場合,検索トランザクション2は,検索にキーAを使用します。この場合,ロールバックの発生によって検索トランザクション1と検索トランザクション2は異なったインデクスキーを使用することになり,検索結果も異なってしまいます。
また,行削除の場合も同様です。コミットするまでデータベースから行データは削除されませんが,その間に同時実行中のほかの検索トランザクションからは検索対象外となります。
このように,コミットしていない削除データが同時実行中のほかの検索トランザクションから検索対象外となる状態は,削除トランザクションがコミットするまで排他を掛けることで回避できます。
- 〈この項の構成〉
(1) 適用基準
次のような業務の場合,コミットしていない削除データに排他を掛けることをお勧めします。
-
先行するトランザクションの処理結果によって,後続のトランザクションの処理が変わる業務
-
ロールバック発生時に再実行を行わない業務
(2) 指定方法
pd_lock_uncommited_delete_dataオペランドにWAITを指定することで,コミットしていない削除データに排他を掛けます。pd_lock_uncommited_delete_dataオペランドについては,マニュアル「HiRDB Version 9 システム定義」を参照してください。
(3) コミットしていない削除データに排他を掛けた場合の効果
コミットしていない削除データに排他を掛けた場合の効果を次に示します。
-
検索中にコミットする前の削除データを検知した場合,検索トランザクションは削除トランザクションのコミット,又はロールバックの決着を待ってから検索処理を行います。これによって,削除トランザクションでロールバックが発生した場合でも,検索トランザクションからの検索読み飛ばしを防止します。
-
インデクスキー値排他と同じ方式で一意性制約が保証されます。これによって,削除トランザクションのロールバック発生時のユニークエラーの検知を防止できます。
(4) コミットしていない削除データに排他を掛けた場合の検索トランザクションの動作
コミットしていない削除データに排他を掛けた場合と掛けなかった場合の検索トランザクションの動作について,SQLの実行条件ごとに,次の表に示します。
項番 |
SQLの実行条件 |
UPDATE文又はDELETE文のトランザクションでROLLBACKが発生した場合の検索トランザクションの動作 |
|||
---|---|---|---|---|---|
同時実行するSQL |
UPDATE文又はDELETE文の内容 |
SELECT文の内容 |
削除データに排他を掛けなかった場合 |
削除データに排他を掛けた場合 |
|
1 |
DELETE文とSELECT文の同時実行 |
行を削除するDELETE文 |
DELETE文で削除するキーが探索条件の範囲に含まれる検索,又は削除した行を参照する検索 |
DELETE文を実行したトランザクションの決着を待たないで削除した行やキーを読み飛ばす |
DELETE文を実行したトランザクションの決着を待って,削除した行やキーを参照する |
2 |
インデクスを定義している表に対し,UPDATE文とSELECT文を同時実行 |
インデクスの更新を伴うUPDATE文 |
UPDATE文で更新するインデクスのキーが探索条件の範囲に含まれる検索 |
UPDATE文を実行したトランザクションの決着を待たないで更新前のキーを読み飛ばす |
UPDATE文を実行したトランザクションの決着を待って,更新前のキーを参照する |
3 |
複数列インデクスを定義している表に対しUPDATE文とSELECT文を同時実行 |
複数列インデクスの一部の列を探索条件に指定し,ほかのインデクス構成列を更新するUPDATE文 |
UPDATE文で更新する複数列インデクスのキーが,探索条件の範囲に含まれる検索 |
UPDATE文を実行したトランザクションの決着を待たないで更新前のキーを読み飛ばす |
UPDATE文を実行したトランザクションの決着を待って,更新前のキーを参照する |
- <項番1の例>
-
項番1の例として,列COL1にインデクスを定義した表TBLのCOL1=1のデータに対し,DELETE文とSELECT文を同時実行した場合を次に示します。
- <項番2の例>
-
項番2の例として,列COL1にインデクスを定義した表TBLのCOL1=1のデータに対し,UPDATE文とSELECT文を同時実行した場合を次に示します。
- <項番3の例>
-
項番3の例として,列COL1とCOL2に複数列インデクスを定義している表TBLのCOL1=1,COL2=1のデータに対し,UPDATE文とSELECT文を同時実行した場合を次に示します。
(5) 注意事項
(a) インデクスの残存エントリ
コミットしていない削除データに排他を掛けた場合,削除,又は更新前のインデクスキーエントリをインデクス内に残すため,ナル値のユニークインデクスキー,及び非ユニークインデクスの残存エントリが発生します。この残存エントリに対して排他待ちが発生した場合,デッドロックが発生することがあります。また,残存エントリが大量にある場合は,検索性能が劣化するおそれがあります。
- ●回避策1:残存エントリを減らす
-
基本的に,残存エントリはインデクスキーが更新,又は削除されるたびに増加します。残存エントリに対する排他待ちやデッドロックを回避するため,一定量の更新,又は削除が発生したら,データベース再編成ユティリティ(pdrorg),又は空きページ解放ユティリティ(pdreclaim)を実行し,残存エントリを削除してください。目安としては,「残存エントリが管理する行数の合計」/「インデクスが管理する総行数」が30%を超えた時点を推奨します。残存エントリの総数は,データベース状態解析ユティリティ(pddbst)を実行して調べてください。
なお,残存エントリは次の場合に削除されます。
-
残存エントリが格納されているページに対してインデクスを追加しようとした場合に,ページ内の空き領域がなくなりインデクスページの分割が発生したとき
-
削除トランザクションの決着後に,そのインデクスに対してpdreclaimコマンドの -xオプションを実行した場合
-
削除トランザクションの決着後に,そのインデクス,又はインデクスに対応する表に対してpdrorgを実行した場合
-
削除したインデクスに対応する表に対してPURGE TABLEを実行した場合
-
削除したインデクス,又はインデクスに対応する表が格納されているRDエリアに対して再初期化を行った場合
また,残存エントリの発生を防ぐには,インデクスの更新頻度を少なくしておくことも有効です。
-
- ●回避策2:残存エントリによる排他待ちを減らす
-
システム共通定義のpd_dbreuse_remaining_entriesオペランドにNOTHING,ONLY_DIC,又は,NONEを指定すると,残存エントリによる排他待ちが少なくなります。詳細は,「残存エントリによる排他待ちの回避(行識別子の再利用抑止)」を参照してください。
(b) 表の残存エントリ
表の行データ格納領域についても,行削除後に残存エントリが発生します。コミットしていない削除データに排他を掛けた場合,これらの残存エントリに対してもチェックを行います。そのため,無効なデータの読み飛ばし処理や,排他制御のオーバヘッドが発生します。
- ●回避策1:残存エントリを減らす
-
インデクスの残存エントリとは異なり,残存エントリに対する予想外の排他待ちは発生しませんが,一定量の更新,又は削除が発生したら,pdrorg,又はpdreclaimを実行し,残存エントリを削除してください。残存エントリの総数は,データベース状態解析ユティリティ(pddbst)を実行して調べてください。
また,残存エントリの発生を防ぐには,行削除の頻度を少なくしておくことも有効です。
- ●回避策2:残存エントリによる排他待ちを減らす
-
システム共通定義のpd_dbreuse_remaining_entriesオペランドにNOTHING,ONLY_DIC,又は,NONEを指定すると,残存エントリによる排他待ちが少なくなります。詳細は,「残存エントリによる排他待ちの回避(行識別子の再利用抑止)」を参照してください。