【実務・中級編】 VACUUM FULLとREINDEX – PostgreSQL

PostgreSQLの「肥大化」と戦う:VACUUM FULLとREINDEXの正しい付き合い方

現場でPostgreSQLを運用していると、避けて通れないのが「テーブルの肥大化(Bloat)」という問題です。

「データはそんなに増えていないはずなのに、ディスク容量がどんどん食われていく……」
「最近、インデックスの検索効率が落ちてきた気がする……」

そんな悩みを抱えたとき、ふと頭をよぎるのが `VACUUM FULL` や `REINDEX` というコマンドですよね。でも、これらには強力な副作用があることを、皆さんは知っていますか?

今回は、これらのコマンドの仕組みと、本番環境で「やらかさない」ための安全な立ち回りについて、僕の経験も交えてお話しします。

—

1. なぜ「物理的な掃除」が必要なのか?

PostgreSQLはMVCC(多版同時実行制御)という仕組みを採用しています。これは、更新や削除が行われても古いデータをすぐには消さず、別のトランザクションから見えるようにしておく仕組みです。

通常の `VACUUM` は、不要になった古いデータ(デッドタプル)を「再利用可能にする」だけで、ディスクから消すわけではありません。そのため、長期間運用していると、テーブルやインデックスの内部に「穴ぼこ」だらけの領域ができてしまうんです。

これが肥大化の正体です。

—

2. VACUUM FULL との付き合い方

`VACUUM FULL` は、テーブルのデータを別の領域にコピーして作り直すことで、物理的な領域を完全に解放します。

  • メリット: 劇的にディスク容量が減る。
  • デメリット: 実行中はテーブルに対して排他ロック(Access Exclusive Lock)がかかる。

つまり、そのテーブルに対しては「読み取り」も「書き込み」も、一切できなくなります。Webサービスでこれを不用意に実行すると、その瞬間からアプリケーションがタイムアウトの嵐になる……なんてことは、新人時代に誰もが一度は経験する(してはいけない)失敗です。

どうしても実行したいときは?

もし、どうしてもテーブルの領域を解放したいなら、PostgreSQL 9.0以降であれば `pg_repack` というOSSツールを検討してください。これはテーブルをコピーする間も読み書きを止めない、まさに魔法のようなツールです。まずはこれを第一選択肢にするのが、現場のエンジニアとしての賢い立ち回りです。

—

3. REINDEX と「CONCURRENTLY」の恩恵

インデックスも同様に、更新を繰り返すとフラグメンテーション(断片化)が進み、検索速度が低下します。ここで使うのが `REINDEX` です。

昔の `REINDEX` は、やはりテーブルをロックしてしまうのが泣き所でした。しかし、PostgreSQL 12からは `REINDEX CONCURRENTLY` が使えるようになったんです。

実践:安全なインデックス再構築

— これが現代のスタンダード。ロックを最小限に抑えて再構築する
REINDEX INDEX CONCURRENTLY idx_users_email;

`CONCURRENTLY` を付けると、PostgreSQLは裏側で新しいインデックスを作成し、最後に古いものと差し替えてくれます。これなら運用中のサービスを止めることなく、インデックスを最適化できます。

ただし、注意点が2つあります。
1. 時間はかかる: 並列で実行するため、通常の `REINDEX` より完了までに時間がかかります。
2. 失敗したときのゴミ: もし何らかの理由で中断されると、無効なインデックスが残ってしまうことがあります。その場合は手動で削除する必要があるので、実行時は必ずログを監視しましょう。

—

4. 先輩エンジニアからのアドバイス

最後に、僕が運用で大事にしているルールを共有します。

  • 「とりあえず実行」は厳禁: `VACUUM FULL` を打つ前に、本当にそれが必要か `pgstattuple` などの拡張機能を使って、どれくらい肥大化しているか可視化しましょう。
  • 自動VACUUMを信じる: ほとんどの場合、適切な `autovacuum` 設定さえあれば、手動の `VACUUM FULL` は不要です。まずは `autovacuum_vacuum_scale_factor` などのパラメータを見直すのが先決です。
  • REINDEXは計画的に: `REINDEX CONCURRENTLY` が使えるとはいえ、負荷がかかることに変わりはありません。CPUやディスクI/Oが空いている時間帯を狙って実行しましょう。

データベースの管理は、庭の手入れに似ています。日々少しずつケアをしていれば大きな作業は不要ですが、一度荒らしてしまうと復旧に多大な労力がかかります。

皆さんのPostgreSQLが、今日も健全に動くことを祈っています!何かあれば、またいつでも聞いてくださいね。

コメント

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