はじめに
デッドロック発生時の調査ポイントについて、思いつくところを書いてみました。
ロックの仕組みについて学ぶ
DB2特有のロックの動作を理解するため、まずは以下の資料を読むことをお勧めします。
DB2デザイン・ガイド: ロックの基礎【V9.7対応】
https://www.ibm.com/developerworks/jp/data/products/db2/design-guide/lock_v97.html
OracleとDB2、ロッキング・メカニズムはこれだけ違うhttp://www.atmarkit.co.jp/ait/articles/0410/06/news118.html
DB2特有のデッドロック発生原因
Oracleとの最大の違いは、DB2は読み取り(SELECT)時にロックが発生しうることでしょう。
A・BテーブルをJOINしたSELECT(共有ロック)を行うトランザクション1と、B⇒Aテーブルの順にUPDATE(排他ロック)をかけるトランザクション2でデッドロックが発生する、なんてこともありうる(SELECT実行のトランザクションでデッドロックエラーが発生したときは、ん?と思ってしまったのだが)。
デッドロック発生時の調査・改善検討ポイント
デッドロックが発生した際に見るべき箇所。
(1)SELECT文の実行計画に問題がないか。
不必要な表スキャン(表ロック)を発生させるような効率の悪いSQLとなっていないか?
表ロックが多いと、前述のようなデッドロックの発生確率が上がる。
[対策]実行計画上、インデックスを使用していない箇所がある場合はインデックスを使用可能なようチューニングできないか、検討する。
(2)LOCK関連のDB構成パラメータが適切か
DB構成パラメータLOCKLIST、MAXLOCKSが極端に小さな値で設定されていないか確認する。
これらは行ロック情報を保持するメモリ領域だが、数値が小さいと、ロックエスカレーション(行⇒表ロックへの格上げ)が発生しデッドロックの可能性が高くなる。
[対策]値が小さい場合は、数値を大きくできないか検討する。
※ただし当パラメータはバージョンによってはAUTOMATIC(最適値に自動チューニング)されるので、AUTOMATIC設定であれば基本的にいじる必要はない。
(3)分離レベルCSで、CUR_COMMITED=ONとなっているか。
分離レベルCSかつ、DB構成パラメータCUR_COMMITED=ON(参照時点でコミットされているデータを参照する)の設定の場合、ロック取得待ちを発生させることがない。
DB2が当設定となっていれば、SELECTによる共有ロック起因でのデッドロックは発生しなくなる(はず!未検証なのでウラがとれたら記事修正します)。
[対策]CUR_COMMITED=DISABLEDの場合、ONに変えることができないか検討する。
その他対策案
思いつくのはこんなとこ?
- SELECTの末尾にWITH URをつけて、ロック取得しないようにする。
(ただし未コミットデータも参照してしまうので業務上問題ないか確認必要) - LOCK TABLE 表名 IN EXCLUSIVE MODE で、先に更新対象テーブルの排他ロックをときっちゃう。
雑感
インフラを触りやすい環境ならよいが、DB構成パラメータ変更はDB全体に効いてくるので変更を嫌がられる可能性あり。その場合は基本的にはSQL修正かインデックス追加などでチューニングしていくしかないかなぁ。
他にもいろいろありそうだけど、書くのに力尽きたので後日加筆します。。