謎のデッドロック
担当機能で、データベース(HiRDB)のデッドロックが起きた。
エラーログによると、テーブル上の論理的な一意キー(物理設計上の制約ではない)で排他ロックをかける SELECT 文にてデッドロックが発生している。
デッドロックは、2つのトランザクションでお互い他方が占有している資源を待ち、膠着状態になることを指す。
したがって、1レコードしかロックしないのであればデッドロックになるはずがない。
HiRDB が内部的に複数レコードをロックしている以外考えられない。
この状況は、ビジネスルール上の論理的なキーと物理設計上のキーが合致しないために生じる。
たとえば:
SELECT ... FROM X WHERE A = '1' AND B = '1'X 表には、
- A = '1' かつ B = '1' のレコード(1)
- A = '1' かつ B = '2' のレコード(2)
があるとする(A はユニークでないインデックス列)。
上の SELECT 文を解析した DB は
- A のインデックスを取得。
- 探索条件 A = '1' に該当する ROWID を特定。
- 対象レコードロック。
- B 列の値を探索条件の B = '1' と比較する。
- マッチしているか?
- マッチしていればクエリの結果セットとして返す。
- マッチしていなければロックを解放する。
- 次対象行があれば 3 に戻る。
という動作を行う。
ポイントはテーブルアクセス時、対象レコードが判定中に更新されないよう DB が内部的にロックをかける点。ここでデッドロックが発生するようなら、SQL レベルで意識されないので厄介だ。