autovacuumとは
PostgreSQLは行をUPDATE・DELETEしても、既存の行を直接書き換えず新しいバージョンの行を追加する。古い行は不要領域(dead tuple)として残り続け、放置するとテーブルとインデックスが肥大化し、検索性能も低下する。autovacuumはこのdead tupleを定期的に回収するバックグラウンドプロセスであり、デフォルトで有効になっている。
autovacuumが正常に機能しているかを確認する方法は主に3つある。
pg_stat_user_tablesで実行履歴を確認するpg_stat_activityで実行中のワーカーを確認する- ログで実行内容を確認する
pg_stat_user_tablesで実行履歴を確認する
pg_stat_user_tablesには、テーブルごとのautovacuum実行状況が記録されている。100万件のテーブルに対して大量のUPDATEを実行した直後の状態を確認する。
SELECT relname, n_live_tup, n_dead_tup, last_autovacuum, autovacuum_count
FROM pg_stat_user_tables
WHERE relname = 'accounts';
relname | n_live_tup | n_dead_tup | last_autovacuum | autovacuum_count
----------+------------+------------+------------------+------------------
accounts | 100000 | 30000 | | 0
n_live_tup: 有効な行数の推定値n_dead_tup: dead tupleの推定値last_autovacuum: 直近でautovacuumが完了した時刻(未実行の場合はNULL)autovacuum_count: autovacuumが実行された累計回数
n_dead_tupが30000まで増えているがautovacuum_countは0のままであり、この時点ではまだautovacuumが実行されていない。デフォルト設定ではn_dead_tupがautovacuum_vacuum_threshold(50) + autovacuum_vacuum_scale_factor(0.2) × n_live_tupを超えるとautovacuum対象になる。このテーブルの場合、閾値は50 + 0.2 × 100000 = 20050であり、条件を満たしているためまもなく実行される。
しばらく待ってから再度確認すると、autovacuumの実行結果が反映されている。
relname | n_live_tup | n_dead_tup | last_autovacuum | autovacuum_count
----------+------------+------------+--------------------------------+------------------
accounts | 100000 | 0 | 2026-07-22 22:08:39.097203+00 | 1
n_dead_tupが0に戻り、last_autovacuumに実行時刻が記録され、autovacuum_countが1に増えている。特定のテーブルでautovacuumが効いているかを確認したい場合は、このビューを見るのが最も手軽である。
pg_stat_activityで実行中のワーカーを確認する
autovacuumが今まさに動いているかどうかは、pg_stat_activityをbackend_type = 'autovacuum worker'で絞り込むと確認できる。300万件のテーブル全体をUPDATEした直後に確認する。
SELECT pid, query, wait_event_type, wait_event
FROM pg_stat_activity
WHERE backend_type = 'autovacuum worker';
pid | query | wait_event_type | wait_event
-----+------------------------------------------------+-----------------+-------------
264 | autovacuum: VACUUM ANALYZE public.big_accounts | Timeout | VacuumDelay
query列にどのテーブルを処理中かが表示される。wait_eventがVacuumDelayになっているのは、I/O負荷を抑えるためにautovacuum_vacuum_cost_delayで設定した時間だけ処理を一時停止している状態であり、異常ではない。実行中のテーブルはpg_stat_user_tablesのlast_autovacuumにまだ反映されないため、完了を待つ必要がある。
ログで確認する
log_autovacuum_min_durationを設定すると、指定した時間以上かかったautovacuumの実行内容がログに出力される。0を指定するとすべての実行が対象になる。
ALTER SYSTEM SET log_autovacuum_min_duration = 0;
SELECT pg_reload_conf();
accountsテーブルに対するautovacuum実行時のログは以下のようになる。
2026-07-22 22:08:39.097 UTC [122] LOG: automatic vacuum of table "postgres.public.accounts": index scans: 1
pages: 0 removed, 576 remain, 576 scanned (100.00% of total)
tuples: 30000 removed, 100000 remain, 0 are dead but not yet removable
removable cutoff: 745, which was 0 XIDs old when operation ended
new relfrozenxid: 732, which is 1 XIDs ahead of previous value
frozen: 0 pages from table (0.00% of total) had 0 tuples frozen
2026-07-22 22:08:39.116 UTC [122] LOG: automatic analyze of table "postgres.public.accounts"
tuples: 30000 removedから、30000件のdead tupleが回収されたと分かる。テーブル単位の統計だけでなく、実際に何件処理されたかまで確認したい場合はログが有効である。本番環境で常時有効にすると出力量が多くなるため、調査時だけ設定するか、log_autovacuum_min_durationにある程度の閾値(例えば1000ms)を設定して長時間かかった実行だけを記録する運用が現実的である。
autovacuumが実行されない場合に確認するパラメータ
n_dead_tupが増え続けているのにautovacuum_countが増えない場合は、以下のパラメータを確認する。
SHOW autovacuum;
SHOW autovacuum_naptime;
SHOW autovacuum_vacuum_threshold;
SHOW autovacuum_vacuum_scale_factor;
SHOW autovacuum_max_workers;
autovacuum:offになっていると全テーブルでautovacuumが動かないautovacuum_naptime: autovacuum launcherがデータベースをチェックする間隔(デフォルト1分)。この間隔でしか対象テーブルを探しに行かないため、直後の反映は期待できないautovacuum_vacuum_threshold/autovacuum_vacuum_scale_factor: 実行対象になるdead tuple数の閾値。大きなテーブルほどscale_factorの影響が大きくなり、実行までに多くのdead tupleが必要になるautovacuum_max_workers: 同時に実行できるautovacuumワーカーの上限(デフォルト3)。テーブル数が多い環境では、この上限に達して処理待ちが発生していないかも確認する
テーブル単位で設定を上書きしている場合はpg_classのreloptionsも確認する。
SELECT relname, reloptions FROM pg_class WHERE relname = 'accounts';
特定のテーブルだけautovacuum_enabled = falseが設定されていると、グローバル設定に関わらずそのテーブルではautovacuumが動かないため、意図した設定か確認する。
