- ブラウザURL入力
- DNS名前→IP
- ルータ経路選択
- ロードバランサ振り分け
- Nginx受け口
- アプリ処理
- DB保存今ここ
ストレージの段で見た「容量」と、ここで言う「空間が空く」は同じではありません。データベースが自分で抱えたまま再利用する層が間に入ります。なお WAL・インデックス・分離レベルはまだ扱っていません。
まず結論
`VACUUM` が必要な理由は、よく語られる2つ(不要行の回収・統計情報の更新)ではありません。PostgreSQL 18 の公式は "several reasons" として**4つ**を番号付きで列挙しています。残る2つを知らないと、なぜ何もしていない表まで掃除されるのかが説明できません。
そしてもう一点。**通常の `VACUUM` はOSにディスクを返しません。** 公式は "extra space is not returned to the operating system (in most cases)" と明記しています。空間は同じ表の中で**再利用可能になるだけ**です。「`VACUUM` すればディスクが空く」は、この形では成り立ちません。
表の途中にある行を大量に `DELETE` したあと通常の `VACUUM` を実行しました。OS から見たディスクの空き容量はどうなるでしょうか。
当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。
「several reasons」と公式は書いている
VACUUM の説明を求めると、たいてい2つの理由が返ってきます。不要になった行を片付けること、そして統計情報を新しくすること。どちらも正しいのですが、公式が挙げている数は2つではありません。
PostgreSQL 18 の routine-vacuuming は、こう始まります。
PostgreSQL's
VACUUMcommand has to process each table on a regular basis for several reasons:
- To recover or reuse disk space occupied by updated or deleted rows.
- To update data statistics used by the PostgreSQL query planner.
- To update the visibility map, which speeds up index-only scans.
- To protect against loss of very old data due to transaction ID wraparound or multixact ID wraparound.
番号が振られて4つです。よく語られる2つは、この並びの前半にあたります。
後半の2つを知らないままだと、説明できない現象が出てきます。3番目は、走査を速くするための地図の更新です。4番目は性質がまったく違います。「非常に古いデータが失われるのを防ぐ」——つまり掃除は片付けであると同時に、データを守る仕事でもあるということです。
この4番目があるために、行を1件も更新していない表にも掃除が必要になります。片付けの理由だけで考えていると、この事実は不可解に見えます。番号の3と4は、5番目以降のレッスンで正面から扱う主題につながります。ここではまず「理由は4つある」という事実を持ち帰ってください。
公式が `VACUUM` の理由として列挙しているのは何個で、よく語られる「不要行の回収」「統計情報の更新」以外に何が含まれますか。
回収するが、返却はしない
ここが本題です。掃除をすればディスクが空く、と考えたくなります。公式 sql-vacuum の記述を順に読みます。
Plain
VACUUM(withoutFULL) simply reclaims space and makes it available for re-use.
空間を回収し、再利用できるようにする。ここまでは期待どおりです。
This form of the command can operate in parallel with normal reading and writing of the table, as an exclusive lock is not obtained.
排他ロックを取らないので、表への通常の読み書きと並行して動きます。本番稼働中に走らせられる掃除です。
そして次の一文が、期待と現実を分けます。
However, extra space is not returned to the operating system (in most cases); it's just kept available for re-use within the same table.
OSには返りません。 同じ表の中で「使ってよい場所」として保持されるだけです。
reclaim 空間を回収する … 通常のVACUUMが行うmark 再利用可能と印を付ける … 通常のVACUUMが行うre-use 同じ表の中で使い回す … 以後のINSERTが使うreturn OSに返す … 通常のVACUUMは行わない
4行目だけが起きません。動詞が違えば意味が違う——reclaim と return を同じ「空く」にまとめた瞬間に、監視グラフを見て慌てることになります。
なお VACUUM にはもう一つの形があり、そちらはOSへの返却を行います。ただし挙動が根本的に違うため、次回まとめて扱います。
通常の `VACUUM` が不要行に対して行うことを、公式の記述に最も近い形で述べているのはどれですか。
通常の VACUUM が行うこと
不要になった行の版を表とインデックスから除き、"marks the space available for future reuse" します。領域そのものは同じ表が抱えたままで、次の `INSERT` がそこに入ります。公式の言葉では "it's just kept available for re-use within the same table" です。
段階 表のファイルサイズ OSの空き容量DELETE 直後 変わらない 変わらないVACUUM 後 変わらない 変わらない次のINSERT 変わらない(再利用) 変わらない
ファイルを消したのに容量が戻らないとき
OSの層でも同じ形が起きます。使用中として開かれている間は、名前を消しても領域は解放されません。使う側が手を離した時点で初めて返ります。「使っている誰かがいる間は返せない」という条件が、層を変えて現れています。
段階 df の空き容量削除前 変わらない名前を消した直後 変わらない使う側が手を離した後 増える
データベースの `VACUUM` と、OSでのファイル削除。層は違いますが、「消したのに空かない」が起きる理由に共通する構造は何でしょうか。
どちらも「消してよいか」の判定と「領域を返すか」の判断が、別のタイミングで行われています。
この章のまとめ
- 公式が挙げる
VACUUMの理由は "several reasons" として4つ。不要行の回収・統計情報の更新・visibility map の更新・周回による非常に古いデータの喪失の防止。通説の2つは前半だけ。 - 古い版が残るのは MVCC の利益を得るために必要だから。"must not be deleted while it is still potentially visible to other transactions"。
- 通常の
VACUUMは "marks the space available for future reuse"。回収(reclaim)はするが返却(return)はしない。 - "extra space is not returned to the operating system (in most cases)"。使用率が下がらないのは失敗ではない。見るべきは増え続けていないか。
- 排他ロックを取らないため "can operate in parallel with normal reading and writing of the table"。
- OSに空間を返すもう一つの形が存在する。挙動が根本的に違うため次回扱う。
自分の現場で確かめる
読んだだけでは身につきません。手元の環境で実際に見てみてください。
理解度チェック
読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。
「`UPDATE` すると古い行はその場で消える」。この説明を公式の記述に照らして評価してください。
用語集(4語)
- VACUUM
- 公式が挙げる目的は4つ。"To recover or reuse disk space occupied by updated or deleted rows." "To update data statistics used by the PostgreSQL query planner." "To update the visibility map, which speeds up index-only scans." "To protect against loss of very old data due to _transaction ID wraparound_ or _multixact ID wraparound_."
- dead row versions(不要になった行の版)
- 更新・削除された行の古い版のうち、"no longer of interest to any transaction" となったもの。通常の `VACUUM` はこれを表とインデックスから除き、"marks the space available for future reuse" する。
- reclaim(回収)と return(返却)
- 公式は書き分けている。通常の `VACUUM` は "simply reclaims space and makes it available for re-use" だが、"extra space is not returned to the operating system (in most cases)"。回収しても返却はしない。
- visibility map
- `VACUUM` の理由の3番目に挙げられる更新対象。公式の記述は "To update the visibility map, which speeds up index-only scans."。索引だけで済ませる走査を速くする役割を持つ。その仕組みは本レッスンでは扱わない。