Dev Study
← データベースの仕組み
レッスン 6 / 13·約 9 分·第6期 データベースの仕組み

先に書くログ — 順序を縛ると、書く回数が減る

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力
  2. DNS名前→IP
  3. ルータ経路選択
  4. ロードバランサ振り分け
  5. Nginx受け口
  6. アプリ処理
  7. DB保存今ここ

ディスクへの書き込みがメモリより桁違いに遅いことは、ストレージの段で扱いました。WAL はここで初めて扱います。

まず結論

データベースは、テーブルの中身を書き換える前に「何をどう書き換えるか」を記録したログを先に永続化します。データファイルへの変更は **それを記述した WAL レコードが永続化された後でなければ書けない**。これが WAL の中核です。

順序を縛るのは不自由に見えますが、**毎回のコミットでデータページをディスクに書かなくてよくなる**という見返りがあります。**制約を受け入れて書き込み回数を減らす交換**になっています。

? 読む前に予測

ログを先に書くという順序を守ると、データベースはディスクへの書き込みについて何が得られるでしょうか。

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

「先に書く」は、順序を縛る約束

WAL の説明は性能ではなく順序の約束から始まります。以下は PostgreSQL 18 時点の公式記述です。

Briefly, WAL's central concept is that changes to data files (where tables and indexes reside) must be written only after those changes have been logged, that is, after WAL records describing the changes have been flushed to permanent storage.

読みどころは only after です。中身が入ったファイルを書き換えてよいのは、その書き換えを記述したログが永続記憶に届いたあとに限られます。

しかも条件は「ログを作った」ではなく flushed to permanent storage です。順序はディスクに届いた時点を基準に縛られています。

一見これは仕事を増やす約束です。ところが公式は見返りも書いています。

If we follow this procedure, we do not need to flush data pages to disk on every transaction commit, because we know that in the event of a crash we will be able to recover the database using the log: any changes that have not been applied to the data pages can be redone from the WAL records.

If we follow this procedure ——この手順に従うならば、という条件付きです。見返りはコミットのたびにデータページをディスクに書き出さなくてよくなること。落ちてもログから復元でき、本体に当たっていない変更は can be redone from the WAL records。だから書き出しを急ぐ理由が消えます。

✓ ここまでの確認

WAL の中核原則として、公式が「順序」について述べているのはどれですか。

具体実物

ログが先、本体が後。逆だと何が分からなくなるか

順序を逆にすると約束の意味がはっきりします。本体を書いてからログを書く手順の途中で電源が落ちたとします。

落ちた瞬間にディスクに残っているもの表
順序 本体(データファイル) ログ(WAL) 復帰時に判断できるか
ログが先(WAL) まだ古い 変更が残る ログから当て直せる
ログが先(WAL) 新しい 変更が残る ログから当て直せる
本体が先(逆) 新しい 何も無い 何が起きたか手掛かりが無い
本体が先(逆) 途中まで新しい 何も無い 手掛かりが無い

下の2行が、順序を逆にしたときに残る状態です。本体だけが変わり、説明する記録がありません。

上の2行は、本体が古くても新しくても構いません。ログが残っていれば当て直せるからです——any changes that have not been applied to the data pages can be redone from the WAL records。

つまり「ログが先」は、本体の状態を気にしなくて済むようにするための約束です。どこまで進んでいるか分からなくてよい自由のために順序を固定している。だからコミットで本体を追いかけずに済みます。

具体実物

WALが想像より膨らむ理由

ここまでだと、WAL には差分だけが入っていそうに思えます。ところが公式の信頼性の解説には、別のものも書かれると明記されています。

To guard against such failures, PostgreSQL periodically writes full page images to permanent WAL storage before modifying the actual page on disk. By doing this, during crash recovery PostgreSQL can restore partially-written pages from WAL.

full page images ——ページ全体のイメージです。しかもこれも before modifying the actual page on disk、実際のページを書き換える前に書かれます。順序の約束が、ここでもう一度使われています。

なぜページ全体が必要なのか。守る相手が部分的に書かれてしまったページだからです。一部だけ新しく残りが古いまま固まった状態は、差分だけでは直せません。土台のページ自体が壊れていて、どこから当てればよいか決まらないからです。ねらいは restore partially-written pages from WAL ——丸ごと戻すには丸ごと持っていなければなりません。

WAL に流れるものの見込みと実際表
想定 WAL に書かれるもの
差分だけと考えた場合 変更した箇所の記述のみ
実際(公式の記述) 変更の記述 + full page images
↑ ページ全体の像も永続 WAL 記憶へ
効いてくる場面 1バイトの書き換えでも、対象ページ全体が流れうる

「小さな更新なのに WAL がよく育つ」というずれは、差分だけを想定すると説明が付きません。なお、どのページがどの頻度で対象になるかは本教材では確認していません。押さえるのは「差分だけではない」一点です。

✓ ここまでの確認

WAL に書かれるのは「変更した差分」だけではありません。部分書き込みに備えて追加で書かれるものはどれですか。

⇄ 2つを見比べる
具体例 A

コミットのたびの書き出しを免除する

先にログを永続化する制約を守ると、コミットの時点でデータページを書き出す義務がなくなります。公式の条件文は “If we follow this procedure, we do not need to flush data pages to disk on every transaction commit”。従うことが免除の前提です。

縛りと見返り表
縛るもの ログが永続記憶に flush されるまで本体を書けない
減るもの コミットごとのデータページ書き出し
根拠 redone from the WAL records(後から当て直せる)
具体例 B

壊れたページを丸ごと戻せるようにする

ページ全体の像を、実際のページを書き換える前に WAL 側へ置きます。公式は “writes full page images to permanent WAL storage _before_ modifying the actual page on disk”。これも「先に書く」順序で、見返りは部分的に書かれたページを復元できること——“can restore partially-written pages from WAL”。

縛りと見返り表
縛るもの 実際のページを書き換える前に full page image を書く
増えるもの WAL の量(差分だけの見込みより膨らむ)
得るもの 部分書き込みされたページを丸ごと復元できる

「コミットで本体を書かなくてよい」と「ページ全体の像を先に書く」。一方は書く量を減らし、もう一方は増やしています。それでも共通している構造は何でしょうか。

どちらも、何かを先に確定させることで、あとの工程で慌てなくて済むようにしています。

この章のまとめ

  • 中核原則は順序の約束。データファイルへの変更は、それを記述した WAL レコードが永続記憶に flush された後でなければ書けない。
  • 見返りは コミットのたびにデータページを書き出さなくてよくなること(we do not need to flush data pages to disk on every transaction commit)。
  • 根拠は復元可能性。本体に当たっていない変更は ログから当て直せる(can be redone from the WAL records)。
  • WAL は差分だけではない。full page images も、ページを書き換える前に書かれる。これが WAL が想像より膨らむ理由。
  • 免除されたのは data pages の書き出しで、WAL レコード自体の flush は免除されていない。「書かない」のではなく書く相手が移った。
  • 以上は PostgreSQL 18 時点の公式記述に基づく。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 3正解: 0

「WAL があるので、コミットのときディスクへの書き込みは一切発生しない」。この説明を公式の記述に照らして評価してください。

用語集(4語)
WAL(Write-Ahead Logging)
公式の中核概念は “changes to data files (where tables and indexes reside) must be written only after those changes have been logged”。変更より先に、その変更を記述したログを永続化する方式。
flushed to permanent storage
公式が順序の条件として使う表現。“after WAL records describing the changes have been flushed to permanent storage”。メモリ上に作った段階では足りず、**永続記憶へ届いた**ことが条件。
redo
公式の言い方は “any changes that have not been applied to the data pages can be redone from the WAL records”。まだ当たっていない変更を、ログから当て直すこと。
full page images
公式は “PostgreSQL periodically writes full page images to permanent WAL storage _before_ modifying the actual page on disk” と書く。差分ではなくページ全体の像。部分的に書かれたページの復元に使う。