「autovacuumは悪ではない」:DBエンジニアが直面するテーブル肥大化の正体と、その処方箋
PostgreSQLを運用していると、必ず一度は「autovacuumに殺される」という感覚を味わうはずだ。特に大規模な書き込みが発生するテーブルで、急にクエリが遅延し、監視ツールが真っ赤になる。その時、多くのエンジニアは「autovacuumを止めて手動で回せばいい」という誘惑に駆られる。
だが、それは禁じ手だ。なぜなら、autovacuumは単なる掃除屋ではなく、PostgreSQLのMVCC(多版同時実行制御)という心臓部を支える重要な自律神経だからだ。
今日は、autovacuumを単なる「デフォルトのまま放置するもの」から、「戦略的に制御するもの」へと昇華させるための話をしよう。
—
なぜautovacuumは「空気を読めない」のか
PostgreSQLのアーキテクチャを理解している諸君なら周知の通り、UPDATEやDELETEは物理的な削除を行わず、古いタプルを「デッドタプル」として残す。autovacuumの役割は、このゴミを回収し、インデックスを整理し、オプティマイザが迷子にならないよう統計情報を更新することだ。
問題は、デフォルトのパラメータが「どんな環境でもそこそこ動く」ことを目的に設定されている点にある。巨大なテーブルや、逆に書き込みが極端に激しいテーブルにおいて、このデフォルト値はあまりに無力だ。
「閾値」という名の心理戦
autovacuumの挙動を左右するのは、主に以下の2つのパラメータだ。
- `autovacuum_vacuum_scale_factor`
- `autovacuum_vacuum_threshold`
デフォルトでは `scale_factor` が `0.2`(20%)に設定されている。これが何を意味するか。1億行のテーブルがあれば、2,000万行が更新されるまでautovacuumは重い腰を上げない。その間に肥大化したテーブルはインデックスの断片化を招き、ディスクI/Oを食いつぶし、クエリプランナーに誤った統計情報を渡すことになる。
結論:大規模テーブルには、絶対的な閾値(`autovacuum_vacuum_threshold`)と、低めの `scale_factor` を組み合わせるべきだ。
数百万行を超えるテーブルであれば、`scale_factor` を `0.01`(1%)程度まで下げ、その分 `autovacuum_vacuum_cost_limit` を引き上げて掃除のスピードを上げるのが、現代のPostgreSQL運用の定石と言える。
—
統計情報の鮮度と「プランナーの誤解」
VACUUMが遅れることは、単にディスク容量が無駄になるだけではない。最悪なのは、統計情報が古くなることだ。
autovacuumは `ANALYZE` も兼ねている。統計情報が最新でないと、クエリプランナーは「このテーブルは小さい」と勘違いし、本来ならインデックススキャンすべきところでシーケンシャルスキャンを選択する。
もし、特定のテーブルで実行計画が頻繁に揺れるなら、まずは `autovacuum_analyze_scale_factor` を疑ってほしい。ここを調整するだけで、多くの「謎の遅延」は解消する。
—
トラブルシューティング:autovacuumとどう戦うか
僕が現場でよく使う、autovacuumを味方にするための「戦術」をいくつか共有しよう。
1. テーブルごとにチューニングを分離せよ
グローバルな `postgresql.conf` をいじるのは最小限に。`ALTER TABLE … SET (autovacuum_vacuum_scale_factor = 0.01)` を使い、アクセス頻度の高い巨大テーブルを個別に最適化するのだ。これが「プロのやり方」だ。
2. `autovacuum_vacuum_cost_limit` の見直し
デフォルトの `200` は少なすぎる。モダンなSSD環境であれば、この値を `1000`〜`2000` 程度まで引き上げても、システム全体のパフォーマンスへの影響は軽微だ。むしろ、短時間で処理を終わらせるほうが、ロック競合の時間を短縮できる。
3. `pg_stat_user_tables` を信じろ
「今、どのテーブルがどれだけ死んでいるか」を把握せずにチューニングはできない。以下のクエリを叩いて、肥大化の兆候を常に監視すべきだ。
SELECT
relname,
n_dead_tup,
last_autovacuum,
last_autoanalyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC;
—
最後に:自動化を恐れるな
僕が駆け出しの頃、autovacuumを止めて夜中に手動でVACUUMを回していた時期があった。しかし、結局のところPostgreSQLのMVCC設計思想に抗うことは、自分自身の首を絞めることに他ならない。
autovacuumは、あなたのDBが健康であるためのバロメーターだ。チューニングとは、彼を「止める」ことではなく、彼が「快適に働ける環境」を整えてやることである。
諸君のデータベースが、今日も健やかにインデックスを整理し続けていることを願っている。何か詰まったら、まずは `pg_stat` を覗いてみてくれ。そこには必ず、解決へのヒントが眠っているはずだ。
コメント