【ライトスキュー】
ライトスキュー とは?
最終更新:
💡 別々の行を書いたのに、合わせるとルール違反になる不意打ち
スナップショット分離のもとで、2つのトランザクションが同じデータを読んで別々の行を更新した結果、それぞれは正しい更新なのに全体の条件(不変条件)が壊れてしまう異常。
📌 このページのポイント
- 同じ集合を読んで判断し、それぞれ別の行を更新するので、書き込みの衝突として検出されない
- 当直医が2人とも休みを取って、当直が0人になる例が有名
- 同じ行への更新が重なるlost updateやdirty writeと違い、書き込む行の集合が重ならない
- 対策はSERIALIZABLEと再試行、競合する全処理で統一した明示ロック、表現可能な条件を守るUNIQUE・排他制約など
ライトスキューって何なの? 書き込みがずれるの?
スナップショット分離で起きる異常の1つだよ。2つのトランザクションが同じデータを読んで「これなら大丈夫」と判断し、それぞれ別の行を更新した結果、全体のルールが破れてしまうんだ。
たとえばどんなことが起きるの?
病院の当直医の例が有名だよ。「当直は常に1人以上」というルールがあって、AliceとBobが当直中とするね。2人が同時に「もう1人いるから休んでも大丈夫」と確認して、それぞれ自分の行を「休み」に更新すると、当直が0人になってしまうんだ。
どうして途中でエラーにならないの?
スナップショット分離では、異なる行への更新だけなら直接の書き込み競合にならないことがあるよ。各自が見ているスナップショットに相手の更新が反映されず、読み取った集合に基づく判断が食い違うんだ。PostgreSQLのREPEATABLE READでは、最初の通常の文を実行した時点の状態を基準にするよ。
ペンギン先生、対策はあるの?
SERIALIZABLEで直列実行と同じ結果を保つ方法があるよ。PostgreSQLでは危険な読み書きの影響関係を検出し、必要ならトランザクションを失敗させる。アプリ側は失敗したSQLだけでなく、トランザクション全体を最初から再試行する。ルールを正しくチェックする処理と、競合する処理の分離レベルをそろえる設計も必要だよ。
SERIALIZABLE以外だとどうするの?
まとめ:ざっくりこれだけ覚えればOK!
「ライトスキュー」って出てきたら「スナップショット分離で、別々の行の更新が合わさって条件を破る異常」と思えればだいたいOK!
📖 おまけ:英語の意味
「Write Skew」 = 書き込みのずれ
💬 書き込み(Write)の結果が、1つずつ順番に実行した場合からずれて(Skew)しまうことから、この名前だよ