【DB2】数千行のテーブルがDELETEできない

※アフィリエイト広告を利用しています
※アフィリエイト広告を利用しています

インフラエンジニアとしてDB2を管理しているのですが、突然開発チームから「100万行のテーブルは消せるのに、数千行のテーブルデータがエラーになって消せないの!助けて!」というこで調べた経緯とかをまとめます。

事象と原因

どんな事象か

「SQL0964C、トランザクションログがいっぱいです」のエラーで削除ができない状態でした。
他には
・五千件程のテーブルのデータを一括DELETEしたらエラーになった。
・その前に別テーブルで数万件のデータは消せた。
・このテーブルは小さいのでログフルにはならないはず
とのことだったので、1回に消すデータを減らして都度commitを入れてもだめ。
1回の削除を100件くらい減らしてもエラーになる。

こんな感じで少ないデータの削除なのにログフルになったことがありました。

原因

結論を先にまとめるのですが、私のところで起きた問題の原因としては、参照制約の削除ルールが「CASCADE」だったため、想定以上の削除が実行されていたようです。

この削除ルールの「CASCADE」は、親テーブル「A」のレコードが削除されると、それに紐づく子テーブルのデータも削除する指定です。
この制約があるため、テーブル「A」の1レコードを削除しようとしても、テーブル「B」で削除するレコードを参照しているのが3レコードあったとしたら、実際は4レコードの削除になる。
ということになります。
さらにテーブル「B」をテーブル「C」が参照していたら。。。と芋づる式に削除するレコードが増えてしまいます。

参照制約 – 削除ルール「CASCADE」のイメージ

これを確認するコマンドは以下のような感じです。

実行するとこんな感じの結果が出力されます。「DELETE_RULE」の結果を確認します。

CONSTRAINT_NAMECHILD_SCHEMACHILD_TABLEDELETE_RULE
SQL231027123456789db2samplORDER_DETAILSCASCADE

「CASCADE」 は上で書いた通り、親テーブルの値を削除すると、子テーブルの値も削除します。
他に
「SET NULL」は親テーブルのレコードを削除すると、参照するカラムはNULLが入ります。
「RESTRICT」は参照している小テーブルがあると、削除が失敗します。

対応

無難なのが参照している子テーブルから削除していく方法かと思います。
それぞれの環境によってベストな方法は変わるかと思います。
全削除するならloadコマンドを制約無視させるとかでも良いかもしれません。

状態確認とその他の要因

状態確認

実際には、結論に至るまで色々確認しましたので、観点と確認方法をまとめます。
まず、他のトランザクションが大量のログを使っていないかを確認しました。

DB2のアクティブログの状態確認

db2pdコマンドで現在のログの状態を確認

結果出力の後半に、各ログファイルの状態が出力されます。
この中で「StartLSN」が「0(実際には000….)」以外のものを確認します。
全てのログが使用状態なら、この値が「0」以外になっているはずです。

トランザクションの状態確認

db2pdコマンドでトランザクションが残っていないか確認します


出力結果の「AppHandle」や「Firstlsn」を確認し、処理中のトランザクションや利用しているログを確認します。

他の要因

他のトランザクションに怪しいものがない場合で、参照制約以外で考えられるのがトリガー設定です。
DELETEが実行されたら、別のテーブルに履歴をINSERTする、といった自動処理が設定がないかを確認します。

まずはトリガーの存在を確認します。SYSCAT.TRIGGERSカタログビューを照会し、対象テーブルにDELETEイベントで発動するトリガーがないか調べました。

何かしらトリガーが設定されていれば、ここでトリガー情報が出力されます

コメント

タイトルとURLをコピーしました