1. データより先にログを書く — WAL
変更はまずメモリ上のページ に書かれ、いつディスクへ流れるかはバッファ管理任せ。ここで停電が来たら? 鍵はログ先行書き込み(WAL) — そのページをディスクへ書く前に、変更を記したログレコードを先にディスクへ 。特にコミット時はコミットログを強制的にディスクへ 吐き出す。こうすれば「ログに在るのにデータに無い」はREDOで直せ、「データに在るのにログに無い」は起こさない。
下で1件の更新(X: 100→150)の流れを動かします。いまクラッシュ を押すと、その瞬間の状態から回復結果が決まります。WAL規則を外す と、ログより先にデータをディスクへ書いてしまい、UNDOできない不整合が生まれる危険が見えます。
ログ先行書き込み — クラッシュの瞬間で運命が決まる
左=メモリ(バッファプール)、中央=ディスクのログ、右=ディスクのデータ。飛ぶ点が「いま書き込んでいる先」。WALありなら必ずログ→データ の順。クラッシュ時、コミットログが届いていればREDOで150を復元(永続性) 、未達なら変更なしで巻き戻し(原子性) 。WAL違反でデータだけ先に届くと、ログ無し=UNDO不能で不整合 に陥ります。
POINT — WALの2つの黄金律
①UNDO則 :変更したデータページをディスクへ書く前に、そのログ(前の値を含む)を先にディスクへ 。②REDO則 :トランザクションをコミット確定とする前に、そのコミットログをディスクへ強制 。この2つを守れば、いつ落ちても「コミット済みは残り、未コミットは消える」を再現できる。ログはシーケンシャル追記なので高速だ。
コミット確定 ⟺ コミットログがディスクに到達
コミット応答を返した=ログが不揮発ストレージに載った、の意味。データページはまだメモリでよい(後でREDOが面倒を見る)。
2. ログには何が書いてあるか — 前の値と後の値
各更新はログレコード として追記されます。中身はLSN(通し番号)・トランザクションID・対象・変更前の値(before)・変更後の値(after) 。この2つの値が回復の材料です — 巻き戻し(UNDO)には前の値、塗り直し(REDO)には後の値 を使う。そしてコミットレコード が書かれた瞬間が「永続化の境界線」です。
ログレコードの中身 — UNDOは前の値、REDOは後の値
▷ 次のログ
全部見せる
↺ リセット
UNDO視点
REDO視点
上から時間順にログが追記されます。各書込レコードは前の値→後の値 を持つ。UNDO視点 では前の値の列が光り「後→前へ戻す材料」、REDO視点 では後の値の列が光り「前→後へ塗り直す材料」。緑のコミット 行から下が確定=永続の境界です。
POINT — 1本のログで前にも後ろにも直せる
before-image があるから、未コミットの変更を逆再生 して消せる(UNDO)。after-image があるから、コミット済みだがディスク未反映の変更を順再生 して復元できる(REDO)。ログは追記オンリーの一本道だが、そこに過去と未来の両方を作り直す情報 が詰まっている。
3. クラッシュからの回復 — REDOとUNDO
再起動時、ログを見て各トランザクションを2組に仕分けます。クラッシュ前にコミット済み=勝者 、まだ未コミット=敗者 。勝者はREDOで前向きに塗り直し (ディスクに届いていない変更を復元)、敗者はUNDOで後ろ向きに巻き戻す (漏れ出た変更を消す)。両方を終えると、ちょうど「コミット済みだけが反映された」一貫状態に戻ります。
下でクラッシュ位置 を動かすと、勝者・敗者の顔ぶれが変わります。回復を実行 すると、REDO(前へ)→ UNDO(後ろへ)の走査が動き、下のデータ項目が正しい値へ収束します。
仕分けて直す — 勝者REDO・敗者UNDO
上段=各トランザクションの区間(●書込・◆コミット)。赤縦線=クラッシュ。線より左でコミットした勝者 は緑、未コミットの敗者 は赤。下段のデータ A〜E は、クラッシュ時にディスクへ中途半端に漏れた状態。REDOで勝者の変更を復元し、UNDOで敗者の変更を消すと、右の「一貫状態」へ揃います。
注意 — REDOは冪等でなければならない
回復の途中でまた落ちることもある。だからREDO/UNDOは何度繰り返しても同じ結果 (冪等)である必要がある。各ページに最後に適用したログ番号(LSN)を記録し、すでに反映済みのログはスキップ する。ARIESの「まず履歴を丸ごと繰り返す(repeating history)」設計は、この冪等性の上に成り立っている。
4. どこまで遡るか — チェックポイント
ログは延々と伸びます。回復のたびに最初から全部走査していては遅い。そこで定期的にチェックポイント を打ち、その時点でダーティなページをディスクへ書き出し、稼働中トランザクションを記録 します。すると回復は直近のチェックポイントから先だけ を見ればよくなる — それより前のコミット済み変更は、もうディスクに載っているからです。
走査範囲を区切る — チェックポイントの効果
緑の縦線=チェックポイント、赤=クラッシュ。左のグレー帯は走査不要 (もうディスクに永続化済み)、右の明るい帯だけがREDO走査範囲 。チェックポイントを右に動かすほど走査が短くなり、回復が速くなります。ただし打つ頻度を上げると通常時の負荷も上がる — 回復時間と平常時コストのトレードオフです。
POINT — チェックポイントは「安全な足場」
それは「ここまでのコミット済み変更は確実にディスクにある」という保証線。回復はここから前向きにREDOを始め、まだ生きていた敗者だけをUNDOすればよい。ファジーチェックポイント を使えば処理を止めずに足場を打てるので、実DBは走らせたまま定期的にこれを刻んでいる。
回復のREDO走査 = [直近チェックポイント, クラッシュ] だけ
それより古いログは読み飛ばせる。チェックポイント間隔が回復時間の上限をほぼ決める。
5. まとめ — 失わないための約束
WAL :データより先にログを書く。コミットはログをディスクへ強制した瞬間に確定する。
ログの中身 :前の値(UNDO用)と後の値(REDO用)。コミット行が永続の境界線。
回復 :勝者をREDOで前へ塗り直し、敗者をUNDOで後ろへ巻き戻す。冪等に。
チェックポイント :走査範囲を区切り回復を速くする。頻度は平常時コストとの綱引き。
一歩先へ — ARIESという定番設計
現代のDBが土台にするのがARIES 。回復は3段階 — 解析(Analysis) でチェックポイント以降を読み勝者・敗者とダーティページを把握し、REDO で「歴史を丸ごと繰り返して」クラッシュ直前の状態を再現し、UNDO で敗者だけを巻き戻す。巻き戻し自体もログに補償ログレコード(CLR) として残すので、UNDOの途中で再クラッシュしても二度手間にならない。ログ番号(LSN)を各ページに刻む一貫した規律が、この複雑な舞台を破綻なく回している。