【実務・中級編】 VACUUMプロセス – PostgreSQL

PostgreSQLのVACUUM、知ってる? 実は超重要!後輩にこっそり教える極意

やあ、みんな!元気にやってるかい?

今日は、PostgreSQLの運用で避けては通れない、でもちょっと奥が深い「VACUUM」について、現場の先輩として、後輩にこっそり教えるつもりで語り尽くそうと思うんだ。

「VACUUMって、なんかよく分からないけど、とりあえず自動でやってくれるんでしょ?」って思ってる、そこの君!ちょっと待って!その考え、もしかしたら将来のボトルネックになるかもしれないぞ。

VACUUM、これがちゃんと分かってると、データベースのパフォーマンスが全然変わってくるんだ。まるで、車のオイル交換みたいなもんだと思ってもらえればいい。定期的にやっておかないと、エンジンの調子が悪くなっちゃうからね。

VACUUMって、一体何をしてるの?

まず、VACUUMの基本的な役割からおさらいしよう。

PostgreSQLでは、データを更新したり削除したりする時、すぐに物理的にディスクから消すわけじゃないんだ。これは、トランザクションの整合性を保つため、あとで「やっぱりこの変更はなかったことに!」ってなったときのために、古いデータ(タプル)を残しておく仕組みがあるから。

で、この「残しておかれた古いタプル」が、どんどん溜まっていくと、色々問題が出てくるんだ。

  • ディスク容量の圧迫: 使わないデータがディスクを占領しちゃう。
  • パフォーマンスの低下: データを検索するときに、無駄な古いデータもスキャンしなきゃいけなくて遅くなる。
  • インデックスの肥大化: インデックスも古いデータと紐づいたままなので、どんどん大きくなっちゃう。

VACUUMは、まさにこの「使われなくなった古いタプル」を片付けて、ディスクスペースを解放してくれる、いわば「お掃除屋さん」なんだ。

さらに、VACUUMはもう一つ、とっても大事な仕事をしてくれる。

それは、「FSM (Free Space Map)」と「VM (Visibility Map)」の更新だ。

FSM (Free Space Map) って何?

FSMは、テーブルやインデックスの各ページに、どれくらいの空きスペースがあるかを記録しているものなんだ。

VACUUMが古いタプルを削除すると、そのスペースが「空いた」ってことになる。FSMはこの空きスペースの情報を更新してくれるから、次に新しいデータが挿入されるときに、効率的にその空きスペースを利用できるようになるんだ。

VM (Visibility Map) って何?

VMは、各ページに格納されているタプルの「可視性」を記録しているもの。つまり、「このページにあるタプルは、どのトランザクションから見えているか」っていう情報だ。

VACUUMが実行されると、古いタプルが削除されて「見えなくなった」タプルが出てくる。VMはこの情報を更新することで、スキャン時に不要なタプルをスキップできるようになり、パフォーマンス向上に繋がるんだ。

自動VACUUMの賢い働き方

さて、ここからが本題。実は、PostgreSQLには「自動VACUUM (Autovacuum)」っていう、とっても賢い仕組みがデフォルトで有効になっているんだ。

「え、じゃあ手動でVACUUMなんてやらなくていいの?」って思った君、甘い!(笑)

自動VACUUMは、一定の条件に基づいて自動的にVACUUMを実行してくれるんだけど、その「一定の条件」が、データベースの状況によってはちょっと緩すぎたり、逆に厳しすぎたりすることがあるんだ。

自動VACUUMが起動するトリガーは、主に以下の2つ。

  • UPDATE/DELETEの回数: テーブルに対するUPDATEやDELETEの操作が、ある一定の閾値を超えると、自動VACUUMのデーモンプロセスが動き出す。
  • テーブルの更新率: テーブルのデータのうち、一定割合以上がUPDATEやDELETEされた場合。

この閾値は、PostgreSQLの設定パラメータで調整できるんだけど、これがまた曲者なんだ。デフォルト値は、色々な環境で使えるように、そこそこ汎用的な値になっている。でも、君たちの運用しているデータベースは、それぞれ個性があるはずだ。

例えば、

  • 書き込みが多いトランザクション処理系のDB: 自動VACUUMが追いつかずに、古いタプルが溜まりやすい。
  • 更新は少ないけど、バッチ処理で大量のデータを削除するDB: 削除後、すぐにVACUUMが走らないと、ディスク容量がなかなか解放されない。

こんな時、デフォルトのままにしておくと、パフォーマンスに悪影響が出たり、ディスク容量が逼迫したりする可能性があるんだ。

実践!VACUUMを使いこなすためのヒント

じゃあ、どうすればいいんだ?って話になるよね。

1. 自動VACUUMの設定を理解し、チューニングする

まずは、自動VACUUMの挙動を理解することが最優先。

`postgresql.conf` には、自動VACUUMに関するたくさんのパラメータがある。代表的なものをいくつか紹介しよう。

  • `autovacuum = on` : 自動VACUUMを有効にするかどうかのフラグ。基本は `on` でOK。
  • `autovacuum_max_workers` : 自動VACUUMを実行するワーカープロセスの最大数。
  • `autovacuum_naptime` : 自動VACUUMデーモンが、次のタスクを探すまでの待機時間。
  • `autovacuum_vacuum_threshold` : テーブルに対するUPDATE/DELETEの回数がこの値を超えると、VACUUMが検討される。
  • `autovacuum_analyze_threshold` : テーブルの統計情報が更新されるべき回数。
  • `autovacuum_vacuum_scale_factor` : テーブルの行数のうち、この割合以上がUPDATE/DELETEされた場合にVACUUMが検討される。
  • `autovacuum_analyze_scale_factor` : テーブルの行数のうち、この割合以上がUPDATE/DELETEされた場合にANALYZEが検討される。

💡現場からのアドバイス:

これらのパラメータは、テーブルごとに個別に設定することもできるんだ。例えば、書き込みの多いテーブルには `autovacuum_vacuum_threshold` や `autovacuum_vacuum_scale_factor` を小さく設定して、より頻繁にVACUUMが走るように調整する、なんてこともできる。

設定の変更は、`ALTER SYSTEM SET parameter_name = value;` で動的に変更できるし、`postgresql.conf` を編集して再起動でもOK。

2. VACUUM ANALYZE の重要性

VACUUMには、`VACUUM ANALYZE` という、もう一つ重要な役割がある。

`ANALYZE` は、テーブルの統計情報を更新する処理だ。PostgreSQLのクエリオプティマイザは、この統計情報をもとに、最も効率的な実行計画を立てる。

もし、統計情報が古いままだと、オプティマイザが間違った判断をしてしまい、本来なら高速なはずのクエリが遅くなってしまう、なんてことも起こりうるんだ。

自動VACUUMは、VACUUM処理とANALYZE処理をセットで実行してくれることが多いんだけど、これも設定次第。

💡現場からのアドバイス:

書き込みが激しいテーブルや、データの更新頻度が高いテーブルでは、`autovacuum_analyze_scale_factor` を小さく設定したり、手動で `ANALYZE` を定期的に実行したりすることを検討しよう。

手動で `ANALYZE` を実行するには、以下のコマンドを使う。

ANALYZE table_name;

あるいは、データベース全体の統計情報を更新するなら:

\x
\timing
VACUUM ANALYZE;
\d+ table_name — テーブルの統計情報などを確認

3. 手動VACUUMの出番

「自動VACUUMがあるなら、手動でVACUUMなんてやる必要ないんじゃないの?」って思った君、それは間違い!

自動VACUUMでは対応しきれないケースもあるんだ。例えば、

  • 大量のデータを一括削除した後: 自動VACUUMが走るまで待っていると、ディスク容量が逼迫してしまう可能性がある。
  • 特定のテーブルだけ、すぐにでもVACUUMしたい場合: 自動VACUUMの設定を待たずに、即座に実行したいとき。

そんな時は、手動で `VACUUM` コマンドを実行しよう。

💡現場からのアドバイス:

  • VACUUM FULL: これは、ディスクスペースを最大限に解放してくれるけど、テーブルのロック時間が長くなるし、テーブルの再構築も行われるので、パフォーマンスに影響が出やすい。運用中のDBで頻繁に実行するのは避けた方が良い。

VACUUM FULL table_name;

  • VACUUM (FREEZE): これは、古いタプルの期限を早める処理。これにより、将来的なVACUUMの負荷を軽減する効果がある。

VACUUM (FREEZE, ANALYZE) table_name;

  • VACUUM (VERBOSE): 実行状況を詳細に表示してくれるので、デバッグや状況把握に役立つ。

VACUUM (VERBOSE, ANALYZE) table_name;

💡現場からのアドバイス:

一番よく使うのは、`VACUUM (ANALYZE)` かな。これで、不要なタプルの削除と統計情報の更新が同時にできるから、パフォーマンス維持に効果的だ。

4. VACUUMの実行状況を監視する

VACUUMがちゃんと動いているか、あるいは遅延していないかは、常に監視しておきたいところだ。

  • `pg_stat_all_tables` ビュー: テーブルごとのVACUUMやANALYZEの実行状況を確認できる。

SELECT
schemaname,
relname,
last_vacuum,
last_autovacuum,
vacuum_count,
autovacuum_count,
last_analyze,
last_autoanalyze,
analyze_count,
autoanalyze_count,
n_dead_tup — 死んでいるタプルの数
FROM
pg_stat_all_tables
WHERE
schemaname NOT IN (‘pg_catalog’, ‘information_schema’)
ORDER BY
n_dead_tup DESC;

  • `pg_stat_activity` ビュー: 現在実行中のVACUUMプロセスを確認できる。

SELECT FROM pg_stat_activity WHERE query LIKE ‘%VACUUM%’;

💡現場からのアドバイス:

`n_dead_tup` (死んでいるタプルの数) が異常に多いテーブルや、`last_autovacuum` が更新されていないテーブルは要注意だ。自動VACUUMが追いついていないか、設定に問題がある可能性が高い。

まとめ:VACUUMは「放置厳禁」!

今日は、PostgreSQLのVACUUMプロセスについて、その役割から自動VACUUMの仕組み、そして現場で役立つチューニングのヒントまで、熱く語ってみた。

「VACUUMって、なんか地味な処理だな…」って思ってた君も、その重要性が少しは伝わったかな?

VACUUMは、データベースの健康診断であり、パフォーマンス維持の要だ。これを「放置厳禁」で、しっかり理解し、適切に管理していくことが、安定したシステム運用には不可欠なんだ。

今回話した内容を参考に、君たちのデータベースのVACUUM戦略を見直してみてくれ。きっと、今まで見えていなかったパフォーマンス改善の糸口が見つかるはずだ。

何か分からないことがあれば、いつでも聞いてくれよな! じゃあ、また!

コメント

タイトルとURLをコピーしました