鍵の新たな死因……?
とりあえずこれまでの経緯をまとめると
- UPDATE文+SELECT文、もしくはUPDATE文+UPDATE文の組み合わせでデッドロックが発生した
- 更新ロックと共有ロックに共通する範囲があり、かつ同時に行われると発生する、変換デッドロックという現象だろうということが判明
- でも、別レコードに対するUPDATE文同士はかちあわないでしょと思っていたら、テーブルにそもそもインデックスが無く、全表走査が発生していたことが判明。
- テーブルに主キーをつけてロック範囲が限定されるようにして更新ロック同士がかちあわないようにし、更にREAD COMMITTED SNAPSHOTをONにして更新ロックと共有ロックがかちあわないように設定。
- そしたら今度は共有ロック同士でデッドロックが発生しちゃった
- どこが「共有」ロックだよバカヤロー
ただ、デッドロックログを見ると、100%SELECT文同士でしか起きていない為、少なくとも更新ロックとかち合うことは無くなったと見ていいかなと(ぽじてぃぶしんきんぐ)。
調べた結果、SELECT文同士でデッドロックは発生することが有るらしい。但し、それはヒントロックを使った更新ロックによるSELECT文同士がかち合った場合らしい。でもなぁ……今回はそんなことしてないし、デッドロックログでも共有ロック(MODE:S)であることは書かれているし、しかもこれはOracleでの事例らしいから、SQLServerで同じことが起きるかどうかは微妙。
ただ気になるのは、このSELECT文は
1:15秒に1回自動的に行う。
2:UPDATE文の処理完了後に1回行う。
の2つの処理で行われるのですが、この2番のパターンでしか端末上ではエラーが発生していないこと。もっと言えば、1番の処理はデッドロックを想定した再起処理を入れていない為、恐らく1番の処理では本当にデッドロックは起きていないんだろうなぁと思われる。
そうなると、2番の処理が複数端末でかち合ったときに、最後のSELECT文でデッドロックが起きているってことになるんだけれど……
……あ、ひょっとして……
プログラマに確認したところ、UPDATEとその後のSELECTは同一トランザクション内で行っているとのこと。
うーん……それは……直感的に言って気持ち悪い。別に根拠は無いのだけれど、UPDATEとSELECTのトランザクションは分けさせた。まあ、トランザクションは可能な限り小さくするのがセオリーですし。
……それ以降、ぱったりデッドロックは起きなくなりましたとさ。
う〜ん……解決……なのか?コレ。
いや、完全に直感で行ったことなので、何かモヤモヤするなぁ……。根拠が無いので、いつかまた再発しそうで怖い。
なので、根拠を作ってみた!
これまた直感だけれど、READ_COMMITTED_SNAPSHOTをONにしたことに関連があるのではないかなぁと考えていたら閃いた!根拠は閃くものなのか疑問だけれど。
もしかすると、UPDATEを含むトランザクションAを実行時に作成されるスナップショットを別トランザクションBで参照する際、AはBの参照時にかけているロックが外れるまでコミット待ちが発生するんじゃないかなと。この考えが正しければ、次の理屈でデッドロックが成り立つなぁと。
- UPDATE→SELECTを1処理とするトランザクションAが実行される。この時、スナップショットAが作成される
- 同時に、UPDATE→SELECTを1処理とするトランザクションBが実行される。この時、スナップショットBが作成される。
- トランザクションAは、UPDATE実行後にSELECTでスナップショットBを参照する。
- トランザクションBは、UPDATE実行後にSELECTでスナップショットAを参照する。
- トランザクションAは、スナップショットAをロックしているトランザクションBが終了するまで自身の終了を待つ
- トランザクションBは、スナップショットBをロックしているトランザクションAが終了するまで自身の終了を待つ
- あら、デッドロックの出来上がり
……うん、後付けで理屈をこぎつけたにしては筋が通っているんじゃなかろうか。恐らく、SELECT文そのものはちゃんと動作するんだろうけれど、そのロックが開放されるのはあくまでトランザクションのコミットが行われた時でしょうしね。確かにデッドロックではあるけど、普通はUPDATE→SELECTを1つのトランザクションにまとめることはしないだろうから(する意味もないし)、これと同一の現象も見当たらない。
このデッドロックって、一応変換デッドロックになるのかなぁ。でも、変換デッドロックとは理屈が違う気が。……ひょっとして新しいタイプのデッドロックを見つけてしまったのではなかろうか。スナップショットデッドロックってな感じの。
時間があったら検証してみるかねぇ
さてさて、理屈が解かったつもりになったところで、この件は一丁上がりってことになりそうかなぁ。
・・・・・・いや、別にその後も発生してないですよ。