【ライトスキュー】

ライトスキュー とは?

最終更新:
💡 別々の行を書いたのに、合わせるとルール違反になる不意打ち

スナップショット分離のもとで、2つのトランザクションが同じデータを読んで別々の行を更新した結果、それぞれは正しい更新なのに全体の条件(不変条件)が壊れてしまう異常。

📌 このページのポイント
別々の行を更新し、全体の条件を破る 条件:当直は1人以上 Alice・Bob 2人が当直 Tx1:Alice Tx2:Bob 2人いると判断 2人いると判断 自分を休みに 自分を休みに 当直が0人に
2人のトランザクションが同じ当直の状態を読み、互いに別の行を休みにする例。スナップショット分離で両方がコミットできる場合を示す。直列実行なら後の処理は休めない。
ひよこ ひよこ
ライトスキューって何なの? 書き込みがずれるの?
ペンギン先生 ペンギン先生
スナップショット分離で起きる異常の1つだよ。2つのトランザクションが同じデータを読んで「これなら大丈夫」と判断し、それぞれ別の行を更新した結果、全体のルールが破れてしまうんだ。
ひよこ ひよこ
たとえばどんなことが起きるの?
ペンギン先生 ペンギン先生
病院の当直医の例が有名だよ。「当直は常に1人以上」というルールがあって、AliceとBobが当直中とするね。2人が同時に「もう1人いるから休んでも大丈夫」と確認して、それぞれ自分の行を「休み」に更新すると、当直が0人になってしまうんだ。
ひよこ ひよこ
どうして途中でエラーにならないの?
ペンギン先生 ペンギン先生
スナップショット分離では、異なる行への更新だけなら直接の書き込み競合にならないことがあるよ。各自が見ているスナップショットに相手の更新が反映されず、読み取った集合に基づく判断が食い違うんだ。PostgreSQLのREPEATABLE READでは、最初の通常の文を実行した時点の状態を基準にするよ。
ひよこ ひよこ
ペンギン先生、対策はあるの?
ペンギン先生 ペンギン先生
SERIALIZABLEで直列実行と同じ結果を保つ方法があるよ。PostgreSQLでは危険な読み書きの影響関係を検出し、必要ならトランザクションを失敗させる。アプリ側は失敗したSQLだけでなく、トランザクション全体を最初から再試行する。ルールを正しくチェックする処理と、競合する処理の分離レベルをそろえる設計も必要だよ。
ひよこ ひよこ
SERIALIZABLE以外だとどうするの?
ペンギン先生 ペンギン先生
当直医の例なら、判断に使う行を更新前にロックする方法があるよ。ただし競合するすべての処理が同じロック規則を守り、必要に応じて再試行する設計が必要なんだ。条件によってはUNIQUE制約や時間範囲の排他制約で競合をDBに調停させられる。普通のCHECK制約や、トリガー内で件数をSELECTするだけでは、複数行にまたがる条件を同時更新から守れるとは限らないよ。該当行が存在しないことを調べる場合も、既存行をロックするだけでは足りないんだ。
ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「ライトスキュー」って出てきたら「スナップショット分離で、別々の行の更新が合わさって条件を破る異常」と思えればだいたいOK!
📖 おまけ:英語の意味
「Write Skew」 = 書き込みのずれ
💬 書き込み(Write)の結果が、1つずつ順番に実行した場合からずれて(Skew)しまうことから、この名前だよ

参考資料

← 用語集にもどる