PostgreSQL メンテナンスガイド
このドキュメントでは、PostgreSQLの定期メンテナンスとテーブル肥大化対策を解説します。
目次
1. メンテナンスの概要
1.1 なぜメンテナンスが必要か
┌──────────────────────────────────────────────────────────────┐
│ メンテナンスが必要な理由 │
├────────────────────────────────────────────────── ────────────┤
│ │
│ 【MVCCによる死んだ行の蓄積】 │
│ │
│ UPDATE文の動作: │
│ 1. 既存行を「削除済み」としてマーク (xmaxを設定) │
│ 2. 新しい行を挿入 │
│ → 古い行が「死んだ行 (dead tuple)」として残る │
│ │
│ DELETE文の動作: │
│ 1. 行を「削除済み」としてマーク │
│ → 実際には削除されず、死んだ行として残る │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ テーブル │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │Live │ │Dead │ │Live │ │Dead │ │Dead │ ... │ │
│ │ │Tuple│ │Tuple│ │Tuple│ │Tuple│ │Tuple│ │ │
│ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ 【問題】 │
│ - ディスク使用量の増加 │
│ - テーブルスキャンの効率低下 │
│ - インデックスの肥大化 │
│ - トランザクションIDの周回問題 │
│ │
│ 【解決策】 │
│ - VACUUM: 死んだ行の領域を再利用可能にする │
│ - ANALYZE: 統計情報を更新してクエリプランを最適化 │
│ - REINDEX: 肥大化したインデックスを再構築 │
│ │
└──────────────────────────────────────────────────────────────┘
1.2 メンテナンス作業の一覧
┌──────────────────────────────────────────────────────────────┐
│ メンテナンス作業一覧 │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌── ──────────────┬────────────────────────────────────────┐│
│ │ 作業 │ 目的 ││
│ ├────────────────┼────────────────────────────────────────┤│
│ │ VACUUM │ 死んだ行の領域を再利用可能にする ││
│ │ VACUUM FULL │ テーブルを完全に再構築 (排他ロック) ││
│ │ ANALYZE │ 統計情報を更新 ││
│ │ REINDEX │ インデックスを再構築 ││
│ │ CLUSTER │ インデックス順にテーブルを再配置 ││
│ │ pg_repack │ オンラインでテーブル/インデックス再構築││
│ └────────────────┴────────────────────────────────────────┘│
│ │
└──────────────────────────────────────────────────────────────┘
2. VACUUM
2.1 VACUUMの種類
┌──────────────────────────────────────────────────────────────┐
│ VACUUMの種類 │
├──────────────────────────────────────────────────────────────┤
│ │
│ 【VACUUM (通常)】 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ - 死んだ行を「再利用可能」としてマーク │ │
│ │ - ディスク容量はOSに返さない │ │
│ │ - テーブルをロックしない (同時に読み書き可能) │ │
│ │ - 比較的高速 │ │
│ │ - 日常的に使用 (Autovacuumで自動実行) │ │
│ └─── ───────────────────────────────────────────────────┘ │
│ │
│ 【VACUUM FULL】 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ - テーブルを完全に再構築 │ │
│ │ - ディスク容量をOSに返す │ │
│ │ - 排他ロック (ACCESS EXCLUSIVE) が必要 │ │
│ │ - 作業中はアクセス不可 │ │
│ │ - 時間がかかる │ │
│ │ - 本当に必要な場合のみ使用 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ 【VACUUM ANALYZE】 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ - VACUUM + ANALYZE を同時実行 │ │
│ │ - 日常的に推奨 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
2.2 VACUUMの実行
-- 全テーブルをVACUUM
VACUUM;
-- 特定テーブルをVACUUM
VACUUM users;
-- VACUUM + ANALYZE
VACUUM ANALYZE users;
-- 詳細出力付き
VACUUM VERBOSE users;
-- VACUUM FULL (排他ロック、注意が必要)
VACUUM FULL users;
-- 並列VACUUM (PostgreSQL 13+)
VACUUM (PARALLEL 4) users;
2.3 VACUUMのオプション
-- PostgreSQL 12+ の構文
VACUUM (
FULL false, -- 通常VACUUM
FREEZE false, -- 強制的にFreeze
VERBOSE true, -- 詳細出力
ANALYZE true, -- 統計情報も更新
DISABLE_PAGE_SKIPPING false, -- 全ページをスキャン
SKIP_LOCKED false, -- ロックされたテーブルをスキップ
INDEX_CLEANUP auto, -- インデックスのクリーンアップ
PROCESS_TOAST true, -- TOASTテーブルも処理
TRUNCATE true, -- 末尾の空ページを切り詰め
PARALLEL 4 -- 並列ワーカー数
) users;
2.4 VACUUMの進捗確認
-- VACUUM の進捗状況
SELECT
p.pid,
p.datname,
p.relid::regclass AS table_name,
p.phase,
p.heap_blks_total,
p.heap_blks_scanned,
p.heap_blks_vacuumed,
ROUND(100.0 * p.heap_blks_vacuumed / NULLIF(p.heap_blks_total, 0), 2) AS progress_pct,
p.index_vacuum_count,
p.max_dead_tuples,
p.num_dead_tuples
FROM pg_stat_progress_vacuum p;
-- Autovacuumの実行状況
SELECT
pid,
datname,
relid::regclass AS table_name,
phase,
heap_blks_total,
heap_blks_scanned
FROM pg_stat_progress_vacuum
WHERE datname = current_database();