モノノフ日記

普通の日記です

データベースのデッドロック

会社の識者がデッドロックについてまとめてくれたので忘れないように転載。
主にSQL Serverの話だけどMySQLでも非常に参考になると思う。

デッドロックには以下の3種類があります。

  1. サイクルデッドロック
  2. 変換デッドロック
  3. テーブルスキャンデッドロック

サイクルデッドロック

最も一般的なのがサイクルデッドロックです。
「行1を更新してから行2を更新」するAさん
「行2を更新してから行1を更新」するBさん

主な回避方法
  • 更新の順序を統一する
  • トランザクションをできるだけ小さく、どうしてもダメならアプリで排他制御

変換デッドロック

トランザクション中のSELECTが絡むのが変換デッドロックです。分離レベルの意識が必要です。
予約系システムなどブッキングすると困っちゃうようなパターンなど。

共有ロックから排他ロックへの変換
「共有ロック(Serializable)でSELECTしてから排他ロックしてUPDATE」したいAさんとBさん
主な回避方法
  • 悲観的制御
    • SELECTを更新ロック(UPDLOCK)で読んで押さえておく
    • ただし、待ちが多くなる。タイムアウトも適切に。
  • 楽観的制御
    • 更新時刻列などを使い更新時に対象を再確認。ダメならごめんなさい。
    • 悲観か楽観かは更新頻度で判断。本来は要求定義で確認。

テーブルスキャンデッドロック

テーブルスキャンで探して排他更新ロックする場合。
一見問題無さそうなアクセス同士でも発生する。
(確かクラスタ化インデックスのフルスキャンでも同様。ORACLEでは起きない、はず。)

主な回避方法
  • 適切なインデックスを張る、使う
  • 楽観的制御で読む
  • SQL2005ならスナップショット分離レベルを使う