PostgreSQLの「お掃除問題」に終止符を。VACUUMとAutovacuumを飼い慣らす技術
「最近、なぜかデータベースのレスポンスが鈍い」「テーブルサイズが肥大化してディスクを圧迫している」……そんな悩みに直面したことはありませんか?
PostgreSQLを長く運用していると、必ずぶち当たる壁が「VACUUM(バキューム)」です。教科書には「不要になった領域を回収する仕組み」としか書いてありませんが、現場で戦うエンジニアからすれば、これは「いかに性能劣化を起こさずに、効率よく老廃物を排出させるか」という、極めて繊細な調整作業です。
今日は、Autovacuumの裏側にあるロジックを紐解きながら、インデックスの肥大化を防ぐための「実戦的なチューニング」について話をしましょう。
—
そもそも、なぜ「掃除」が必要なのか?
PostgreSQLのMVCC(多版同時実行制御)は、更新や削除のたびに新しい行を作り、古い行を「デッドタプル」として残します。これが溜まると、フルスキャン時のコストが跳ね上がるのはもちろん、インデックスの肥大化(Bloat)を引き起こします。
ここで登場するのがAutovacuumです。彼らはバックグラウンドで黙々と働いてくれる頼もしい奴らですが、デフォルト設定のまま放置すると、大規模なテーブルでは「掃除が追いつかない」という事態に陥ります。
—
Autovacuumをチューニングする3つの鍵
Autovacuumを制御するパラメータはいくつかありますが、まずは以下の3つを重点的に見ていきましょう。
1. `autovacuum_vacuum_scale_factor`:掃除のタイミングを決める
デフォルトは `0.2`(テーブルの20%が変更されたら掃除する)です。
現場の教訓: 1億行あるテーブルで「20%」は、2,000万行の更新です。これだと掃除の頻度が低すぎて、デッドタプルが山積みになります。
- 大規模テーブルでは、この値を `0.01` 〜 `0.05` くらいまで下げて、こまめに掃除させるのが定石です。
2. `autovacuum_vacuum_cost_limit`:掃除の「激しさ」を決める
Autovacuumが一度のサイクルでどれだけ仕事をしていいかの上限値です。
- デフォルトの `200` は少し控えめすぎます。最近の高速なNVMe SSDを使っている環境なら、`1000` くらいまで引き上げても問題ありません。ここをケチると、掃除が追いつかずにテーブルが肥大化します。
3. `autovacuum_vacuum_cost_delay`:掃除の「休憩時間」を決める
各作業の合間に入れる休憩時間です。
- ここを `0` にして完全に休憩をゼロにするか、あるいは `2ms` 程度に抑えることで、インデックスの更新効率を劇的に改善できます。
—
設定変更の実践例
全体設定をいじるのが怖い場合は、特定のテーブルに対して個別に設定するのが「現場の賢いやり方」です。
— 肥大化しやすい大規模テーブルへの個別の調整
ALTER TABLE orders SET (
autovacuum_vacuum_scale_factor = 0.01,
autovacuum_vacuum_cost_limit = 1000,
autovacuum_vacuum_cost_delay = 2
);
こうすることで、他の小さなテーブルには影響を与えずに、特定の「暴れん坊テーブル」だけを重点的にケアできます。
—
インデックス肥大化との戦い方
実は、VACUUMがいくら頑張っても、インデックスの肥大化を完全には防げないことがあります。インデックスはデータそのものより複雑な構造(B-Tree)を持っているため、断片化しやすいのです。
もし、「掃除はしているのにクエリが遅い」と感じたら、まずは `pgstattuple` 拡張を使って、インデックスの空き領域率を確認してみてください。
— インデックスの断片化を確認する
CREATE EXTENSION pgstattuple;
SELECT FROM pgstatindex(‘index_name’);
ここで `avg_leaf_density`(リーフページの密度)が極端に低い場合は、`REINDEX CONCURRENTLY` でインデックスを張り直すのが一番の特効薬です。
—
先輩からのアドバイス:焦ってはいけない
最後に一つだけ。Autovacuumを「速くすればするほど正義」と考えるのは危険です。過剰な掃除はI/O負荷を跳ね上げ、本番のクエリを阻害します。
1. まずは現状のデッドタプル数を確認する(`pg_stat_user_tables` を見る)。
2. ログでAutovacuumの実行頻度と時間を追う(`log_autovacuum_min_duration` を設定する)。
3. 少しずつパラメータを弄り、変化を楽しむ。
データベースのチューニングは、いわば盆栽のようなものです。いきなり劇的な変化を求めず、じっくりと環境と対話しながら調整していってください。
もし、運用中に「Autovacuumが動いているのにディスクが減らない!」なんてパニックになったら、それは大抵 `long transaction`(放置されたトランザクション)が原因です。その話はまた別の機会にじっくりと。
それでは、良いPostgreSQLライフを!
コメント