PostgreSQLの「お掃除」と「健康診断」を一度に:VACUUM ANALYZEとの付き合い方
現場でPostgreSQLを触っていると、たまに耳にしませんか?「最近、なんだかクエリが遅い気がする」「実行計画がどうもおかしい」というボヤキ。
そんな時、真っ先に疑うべきなのが「統計情報の鮮度」と「不要領域(デッドタプル)の蓄積」です。この2つを一度に解決してくれるのが、今回の主役である `VACUUM ANALYZE` コマンド。
教科書的には「ガベージコレクションと統計情報の更新」なんて書かれていますが、もっとシンプルに言えば、「DBのゴミを捨てて、最新の地図(統計情報)に書き換える」という、エンジニアなら避けて通れないメンテナンス作業なんです。今日は、これを現場でどう扱うべきか、本音で話していきますね。
—
なぜ「VACUUM」だけじゃダメなのか?
まず前提として、PostgreSQLは追記型のアーキテクチャ(MVCC)を採用しています。データを更新・削除しても、古いデータは即座に物理削除されず、そのまま「ゴミ」として残ります。これが「デッドタプル」です。
- VACUUM: このゴミを掃除して、領域を再利用可能にする。
- ANALYZE: テーブルのデータ分布を調査し、「どのインデックスを使うのが一番効率的か」をプランナに教える。
この2つを分けると手間ですよね。そこで登場するのが `VACUUM ANALYZE` です。一度のコマンドで「掃除」と「健康診断」を終わらせる。まさに一石二鳥のコマンドです。
—
実践:どういうタイミングで使うべき?
本来、PostgreSQLには `autovacuum` という強力な自動掃除機能がついています。設定さえ適切なら、基本的には放っておいても大丈夫。
でも、「現場のエンジニアが手動で叩くべきタイミング」は確実に存在します。
- 大量のDELETE/UPDATE直後:
数百万件単位でデータをバッチ処理した直後。自動起動を待たずに掃除してあげないと、その後の検索クエリが悲鳴を上げます。
- プランナが明らかに「下手な道」を選んでいる時:
`EXPLAIN` を見て、「おっと、ここはインデックスを使うべきなのに、なぜフルスキャンしてるんだ?」という時。統計情報が古くて、プランナがテーブルの密度を見誤っている可能性が高いです。
- システムのリリース直前:
本番環境へ移行する際、テストデータを流し込んだ後などには一度実行しておきましょう。
—
書き方と注意点
使い方はいたってシンプルです。
— 特定のテーブルだけを対象にする場合
VACUUM ANALYZE verbose users;
— データベース全体を一気にやる場合(慎重に!)
VACUUM ANALYZE;
ここで一つ、僕からのアドバイス。`VERBOSE` オプションを付ける癖をつけてください。
VACUUM ANALYZE VERBOSE users;
これを付けると、どれくらいのゴミが掃除され、どれくらいのページが再利用可能になったか、ログに細かく出力されます。「よし、ちゃんと綺麗になったな」と確認できるだけで、夜も安心して眠れますよね。
注意:ロックの話
`VACUUM ANALYZE` はテーブルを完全にロックするわけではないので、読み書きは可能です。ですが、大量のゴミがあるテーブルで実行すると、I/O負荷が跳ね上がります。ピークタイムに実行するのは絶対にNGです。 必ずトラフィックが落ち着いている時間帯を選んでください。
—
最後に:自動化を過信しないこと
最近のPostgreSQLは優秀なので、`autovacuum` がほとんどのケースをカバーしてくれます。ですが、たまに「autovacuumが追いついていないテーブル」を見つけることがあります。
そんな時は `pg_stat_user_tables` を覗いてみてください。
SELECT relname, n_dead_tup, last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC;
これで「死体(デッドタプル)」が溜まっているテーブルが一目瞭然です。「お、お前、掃除をサボってるな?」と気づいてあげることが、良いDBAへの第一歩です。
データベースは、一度作ったら終わりではありません。こまめに手入れをしてあげることで、その実力を発揮してくれます。ぜひ、コマンドを打つときは「いつもありがとう」という気持ちで、メンテナンスしてあげてくださいね。
それでは、また現場で!
コメント