PostgreSQLを本番で自前運用していると、こういう状況に直面することがあります。autovacuumの自動処理だけでは追いつかないタイミングで、手動による強制クリーンアップが必要になる場面です。
この記事では、PostgreSQLに同梱されているコマンドラインツール
vacuumdb の実践的な使い方を解説します。単一データベースへの通常VACUUMからFULL VACUUMによる物理領域の回収、全データベース一括クリーンアップ、cronを使った定期実行の設計まで、RHEL 9.4 / Ubuntu 24.04 LTS(PostgreSQL 16)で動作確認した手順をそのままお届けします。
この記事のポイント
・vacuumdbはVACUUM SQLをCLIから実行するPostgreSQL付属のコマンド
・--fullオプションでテーブルを書き直し、OS側にディスク領域を返却できる
・--allで全データベースを一括クリーンアップし、メンテナンスを効率化できる
・--jobs=Nで複数テーブルを並列処理し、大規模DBの処理時間を短縮できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
vacuumdbとは何か(autovacuumとの役割分担)
vacuumdb はPostgreSQLに同梱されているクライアントユーティリティです。内部ではPostgreSQLに接続してSQL VACUUM文を実行しているラッパーで、シェルスクリプトやcronから直接呼び出せる点が強みです。autovacuumとvacuumdbの役割を整理すると、次のように使い分けるのが現場の定石です。
| 項目 | autovacuum | vacuumdb |
|---|---|---|
| 起動タイミング | デッドタプル率が閾値を超えたとき自動起動 | 手動・cron等で任意のタイミングで実行 |
| VACUUM FULL | 実行しない(通常VACUUMのみ) | --fullオプションで実行可能 |
| 全DB一括処理 | 各DBを個別に処理 | --allオプションで全DBを一括処理 |
| 主な用途 | 日常的な不要領域の回収・統計更新 | 定期メンテナンス・物理領域の回収・緊急対応 |
VACUUM FULLは物理的にテーブルを書き直してOSにディスク領域を返却します。一方、通常のVACUUMはデッドタプルを「再利用可能」とマークするだけで、ディスク領域はPostgreSQLが保持し続けます。肥大化したテーブルのサイズを実際に縮小したいときは、
vacuumdb --full が必要です。
実行前の確認 — デッドタプル量を把握する
vacuumdbを実行する前に、まずどのテーブルがどれだけデッドタプルを抱えているか確認します。pg_stat_user_tables ビューが参照先です。# PostgreSQLに接続してデッドタプル量を確認する sudo -u postgres psql -d mydb -c " SELECT relname, n_live_tup, n_dead_tup, round(n_dead_tup::numeric / NULLIF(n_live_tup + n_dead_tup, 0) * 100, 1) AS dead_pct, last_vacuum, last_autovacuum FROM pg_stat_user_tables WHERE n_dead_tup > 1000 ORDER BY n_dead_tup DESC LIMIT 10;"
relname | n_live_tup | n_dead_tup | dead_pct | last_vacuum | last_autovacuum --------------+------------+------------+----------+--------------------------+---------------------------- orders | 312041 | 87432 | 21.9 | 2026-09-14 03:00:02+09 | 2026-09-15 01:22:15+09 access_logs | 1204550 | 34218 | 2.8 | | 2026-09-15 00:15:42+09 sessions | 42100 | 12890 | 23.4 | | 2026-09-14 23:48:10+09 (3 rows)
last_vacuum が空(手動VACUUMを実施していない)のテーブルも確認しておきます。テーブルの現在のサイズも把握しておくと、FULL VACUUM後の効果を数値で確認できます。
# テーブルサイズを確認する(FULL VACUUM前後の比較用) sudo -u postgres psql -d mydb -c " SELECT relname, pg_size_pretty(pg_relation_size(relid)) AS table_size, pg_size_pretty(pg_total_relation_size(relid)) AS total_size FROM pg_stat_user_tables ORDER BY pg_total_relation_size(relid) DESC LIMIT 10;"
vacuumdbの基本的な使い方
1. 対象データベースを指定して実行する
最も基本的な実行形式です。postgres システムユーザーに切り替えてから実行するのが通常の手順です。# postgresユーザーに切り替え sudo -u postgres vacuumdb mydb # または sudo -u postgres を毎回付ける形でも可 sudo -u postgres vacuumdb --verbose mydb
--verbose(または -v)を付けると各テーブルの処理状況がリアルタイムで出力されます。INFO: vacuuming "public.orders" INFO: scanned index "orders_pkey" to remove 87432 row versions INFO: "orders": removed 87432 row versions in 10929 pages DETAIL: CPU: user: 1.23 s, system: 0.08 s, elapsed: 3.41 s INFO: "orders": found 87432 removable, 312041 nonremovable row versions in 19854 of 19854 pages DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 4290123 INFO: vacuuming "public.access_logs" ... vacuumdb: vacuuming database "mydb"
2. --analyzeで統計情報を同時に更新する
--analyze(または -z)オプションを付けると、VACUUMと同時にプランナ統計情報も更新します。クエリの実行計画がずれていると感じたときは、このオプションを必ず付けて実行してください。# VACUUMとANALYZEを同時実行 sudo -u postgres vacuumdb --analyze --verbose mydb # 特定テーブルだけ対象にする場合 sudo -u postgres vacuumdb --analyze --table=orders mydb
--analyze-only(または -Z)オプションを使うとVACUUMをスキップしてANALYZEだけを実行します。デッドタプルは少ないが統計が古いという状況で有効です。3. --allで全データベースを一括クリーンアップする
--all(または -a)オプションを指定すると、サーバー内のすべてのデータベースを順番にVACUUMします。週次メンテナンスで全DBをまとめて処理したいときに使います。# 全データベースをVACUUM + ANALYZE sudo -u postgres vacuumdb --all --analyze --verbose
4. フルバキュームで物理領域を回収する(--full)
通常のVACUUMはデッドタプルを再利用可能とマークするだけですが、--fullオプションを付けるとテーブルを物理的に書き直してOSにディスク領域を返却します。# FULLバキュームを実行(実行前にordersテーブルがロックされることに注意) sudo -u postgres vacuumdb --full --analyze --verbose --table=orders mydb
# FULL VACUUM前のサイズ確認 sudo -u postgres psql -d mydb -c "SELECT pg_size_pretty(pg_relation_size('orders'));" pg_size_pretty ---------------- 3721 MB # vacuumdb --full 実行後(数分後) sudo -u postgres psql -d mydb -c "SELECT pg_size_pretty(pg_relation_size('orders'));" pg_size_pretty ---------------- 2108 MB
重要:VACUUM FULLの注意点
VACUUM FULLはテーブルに対して
ACCESS EXCLUSIVE ロックを取得します。実行中は、そのテーブルへのSELECT・INSERT・UPDATE・DELETE・すべての操作がブロックされます。本番環境で実行する場合は必ずメンテナンスウィンドウを設けてください。テーブルサイズが大きいほど処理時間も長くなります(1GBのテーブルで数分~十数分程度)。
--freezeオプション — XID周回対策の強制フリーズ
PostgreSQLのトランザクションIDは32ビット(約21億件)で周回します。古いタプルのXIDが周回点に近づくと、PostgreSQLは自動的にアグレッシブなVACUUM(freeze)を実行しますが、負荷が高い本番環境では計画的に実行する必要があります。まずXIDの残り余裕を確認します。
# データベースごとのXID周回余裕を確認 sudo -u postgres psql -c " SELECT datname, age(datfrozenxid) AS xid_age, 2100000000 - age(datfrozenxid) AS xid_remaining FROM pg_database ORDER BY age(datfrozenxid) DESC;" datname | xid_age | xid_remaining -------------+-----------+--------------- mydb | 801234567 | 1298765433 template1 | 45678901 | 2054321099 postgres | 45678890 | 2054321110
# 強制フリーズを実行(全DB対象) sudo -u postgres vacuumdb --all --freeze --verbose
--jobsオプションによる並列実行(PostgreSQL 9.5以降)
--jobs=N(または -j N)オプションを指定すると、複数のテーブルを並列にVACUUMします。大規模なDBでメンテナンス時間を短縮したいときに有効です。# 4つの接続を並列で使ってVACUUMを実行 sudo -u postgres vacuumdb --jobs=4 --analyze --verbose mydb
max_connectionsの残量を確認してから実行してください。# 現在の接続数とmax_connectionsを確認 sudo -u postgres psql -c "SELECT count(*) AS current_conn, (SELECT setting::int FROM pg_settings WHERE name='max_connections') AS max_conn FROM pg_stat_activity;" current_conn | max_conn --------------+---------- 42 | 100
なお、
--fullとの組み合わせは使えません。VACUUM FULLはテーブル単位で排他ロックを取るため、並列化しても実質的に順次処理になります。
cronで定期実行する設計
vacuumdbの定期実行は、autovacuumが追いつかない大量更新・削除が発生する環境や、メンテナンスウィンドウが設けられたシステムで特に有効です。以下は週次でFULL VACUUMを実行するcrontabの設定例です。
# /etc/cron.d/postgresql-vacuumdb(postgresユーザーで実行) # 毎週日曜3:00にFULL VACUUM + ANALYZE(全DB) 0 3 * * 0 postgres /usr/bin/vacuumdb --all --analyze --verbose 2>&1 | logger -t vacuumdb # 毎日2:00に通常VACUUM + ANALYZE(mydbのみ) 0 2 * * * postgres /usr/bin/vacuumdb --analyze mydb 2>&1 | logger -t vacuumdb
loggerコマンドでsyslogに流しておくと、journalctlで実行結果を後から確認できます。# vacuumdbのcron実行ログを確認する journalctl -t vacuumdb --since "2026-10-05 02:00:00" --until "2026-10-05 04:00:00"
which vacuumdb または rpm -ql postgresql-server | grep vacuumdb で確認してください。PostgreSQLの実務運用スキルを体系的に身につけたい方には、Linux Master Pro Seminarのカリキュラムもあわせてご確認ください。サーバー構築からDB運用・トラブル対応まで2日間のハンズオンで実践できます。
トラブルシュート — よくあるエラーと対処法
「ERROR: canceling autovacuum task」が出てVACUUMが止まる
VACUUM FULLが実行中に、autovacuumが割り込んで中断させることがあります。これはautovacuumがロックを競合したときに自分を犠牲にする設計によるものです。# FULLの前にautovacuumを一時停止する(postgresqlの設定変数を確認) sudo -u postgres psql -d mydb -c "SET autovacuum = off;" # この方法はセッションローカルのみ有効。DBレベルで止める場合 sudo -u postgres psql -c "ALTER SYSTEM SET autovacuum = off;" sudo -u postgres psql -c "SELECT pg_reload_conf();" # vacuumdb実行後に必ず戻す sudo -u postgres psql -c "ALTER SYSTEM SET autovacuum = on;" sudo -u postgres psql -c "SELECT pg_reload_conf();"
「vacuumdb: too many parallel jobs requested」
--jobs=N でNがmax_connectionsの残余を超えると接続に失敗します。# エラーメッセージ例 vacuumdb: error: too many parallel jobs requested (10), maximum is 58 # 解決策: jobsの数をmax_connections残余以内に収める sudo -u postgres vacuumdb --jobs=4 --analyze mydb
「Permission denied」でvacuumdbが実行できない
vacuumdbはデータベースへの接続権限が必要です。postgres システムユーザーで実行していない場合に発生します。# NG: rootで直接実行する root# vacuumdb mydb vacuumdb: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "root" does not exist # OK: postgresユーザーに切り替えてから実行する root# sudo -u postgres vacuumdb mydb
VACUUM FULLが終わらない(長時間処理)
VACUUM FULLはテーブルを書き直すため、テーブルサイズに比例した時間がかかります。別セッションから進捗を確認できます。# vacuumdbの進捗を確認する(PostgreSQL 9.6以降) sudo -u postgres psql -c " SELECT relid::regclass AS table_name, phase, heap_blks_scanned, heap_blks_total, round(heap_blks_scanned::numeric / NULLIF(heap_blks_total, 0) * 100, 1) AS pct FROM pg_stat_progress_vacuum;" table_name | phase | heap_blks_scanned | heap_blks_total | pct ----------------------+--------------------+-------------------+-----------------+------- public.orders | vacuuming heap | 34512 | 47684 | 72.4
pg_stat_activity でwait_event列を確認してください。
本記事のまとめ
vacuumdbの主要オプションとユースケースをまとめます。| やりたいこと | コマンド |
|---|---|
| 指定DBにVACUUMを実行する | vacuumdb mydb |
| VACUUM + ANALYZEを同時実行する | vacuumdb --analyze mydb |
| 全データベースを一括クリーンアップする | vacuumdb --all --analyze |
| 物理領域を回収する(テーブルロックあり) | vacuumdb --full --analyze mydb |
| 特定テーブルだけ対象にする | vacuumdb --table=orders mydb |
| XID周回対策の強制フリーズ | vacuumdb --all --freeze |
| 複数テーブルを並列処理する | vacuumdb --jobs=4 --analyze mydb |
| 処理状況を詳細出力する | vacuumdb --verbose mydb |
autovacuumは日常的なメンテナンスをカバーしますが、大量削除・更新後の緊急対応やFULL VACUUMによるディスク領域回収は
vacuumdb を使った手動実行が必要です。定期メンテナンスにはcronからvacuumdbを呼び出す設計が現場では一般的です。
>> Linux Master Pro Seminarの詳細を見る
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:PostgreSQL・MySQLのストレージエンジンとロック機構の違い|Linuxセルフホスト選定の実践基準
- この記事の属するカテゴリ:データーベース管理へ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます