徹底解説シリーズ

中級 PostgreSQL 完全攻略

なんとなく使っている PostgreSQL の中身を、徹底的に解説する

POSTGRESQL INTERMEDIATE DEEP-DIVE
📅 2026 年版PG 16+初心者〜中級エンジニア向け
このページは一部有料です
Section 01 — 08(G1・G2)は無料で読めます。Section 09 以降(G3 〜 G13)は有料です。
PAID CONTENT
約 10 万字
ABOUT THIS GUIDE

はじめに

この記事は初心者から中級のエンジニアを、本番運用に耐えるレベルまで一気に引き上げる徹底解説です。全 47 セクション・13 グループにわたって、PostgreSQL の基礎・アーキテクチャ・MVCC・WAL・インデックス・実行計画・レプリケーション・バックアップ・セキュリティまでを、図解とインタラクティブツール、そして実際のコマンド例とともに扱います。

PostgreSQL の世界では、「初歩の入門教材」と「すでにベテラン向けの濃すぎる解説」は豊富にあるものの、その間を埋める中級レベルの教材がほとんど存在しません。入門書を読み終えた後、本番運用に出ていく前に何を学べばいいのか分からない — そういう空白を埋めるための記事です。

したがって対象は中級者だけではありません。SQL を最低限触ったことがある初心者でも、最初の章で基礎をおさらいしてから読み進められるよう構成してあります。「動いている DB の中身がどうなっているのか、ちゃんと理解した状態で本番に出たい」というすべての人に向けて書きました。

この記事で身につく力
EXPLAIN ANALYZE を読んでスロークエリの原因を自力で特定できる
MVCC / WAL / Autovacuum の挙動を理解して運用判断ができる
本番の Autovacuum をテーブル特性に合わせてチューニングできる
インデックス 6 種を目的別に使い分けられる (B-tree / GIN / GiST / BRIN ほか)
Streaming Replication と Logical Replication を構築・運用できる
バックアップ・リストア・PITR を正しい手順で実施できる
PgBouncer と接続プーリングを本番規模に合わせて設計できる
ロール / 権限 / RLS でセキュアな DB を設計できる
本番運用ミス 15 大パターンを事前に予防できる
対象読者
・PostgreSQL の入門書 / 入門記事を読み終えて、次に何を学ぶべきか迷っている初心者
・SQL は書けるが MVCC や WAL の仕組みは把握できていない人
・本番運用しているが「動いている」止まりで、内部がブラックボックスな人
・スロークエリや bloat、レプリ遅延の原因を自力で追えるようになりたい人
・PostgreSQL を真面目に身につけたいが、ちょうどいい中級レベルの教材が見つからずに困っている人
TABLE OF CONTENTS

目次

全 13 グループの構成です。基礎から順に積み上げていきますが、興味のあるグループから読み始めても OK です。無料有料の境目も合わせて記載しています。

G1
PostgreSQL の全体像と基礎
Section 01 — 02
基礎おさらい・他 RDBMS 比較・階層構造・データ型・psql・主要 SQL・トランザクション・クエリ実行 5 ステージ
無料
G2
アーキテクチャ
Section 03 — 08
プロセスモデル・Postmaster・Backend 内部・バックグラウンドプロセス全 14 種・メモリ構造・設定ファイル
無料
🔒 ここから有料
G3
テーブル設計とストレージ基礎
Section 09 — 14
テーブル設計・タプルと物理レイアウト・MVCC・WAL・VACUUM・Autovacuum
🔒 有料
G4
クエリ実行と EXPLAIN
Section 15 — 17
5 ステージ詳細・EXPLAIN の読み方・プランナーのコスト計算
🔒 有料
G5
インデックス
Section 18 — 23
6 種比較・B-tree 内部・GIN / GiST・部分 / 関数 / 複合 index・アンチパターン・REINDEX / pg_repack
🔒 有料
G6
並行制御
Section 24 — 26
分離レベル 4 種・ロックの種類・デッドロック (シミュレータ付き)
🔒 有料
G7
パフォーマンスチューニング
Section 27 — 29
pg_stat_* / スロークエリ対処 / メモリ設定の見直し
🔒 有料
G8
スケールアウトと高可用性
Section 30 — 34
パーティショニング・Streaming / Logical Replication・負荷分散・Patroni HA
🔒 有料
G9
運用
Section 35 — 39
バックアップ全 7 種・リストア・監視・PgBouncer・アップグレード戦略
🔒 有料
G10
高度な機能
Section 40 — 42
JSONB と GIN・Window 関数 / CTE・PL/pgSQL
🔒 有料
G11
セキュリティ
Section 43 — 45
ロールと権限・RLS・SSL/TLS と認証方式
🔒 有料
G12
よくある運用ミス 15 選
Section 46
本番でやらかしがちな失敗を「何が起き / なぜ / どう直すか」セットで
🔒 有料
G13
締めくくり
Section 47
ここまでのおさらいと、さらに深掘りしたい人への案内
🔒 有料
1
GROUP 1Section 01 — 02
PostgreSQL の全体像と基礎
まず PostgreSQL がどんな DB なのか、その全体像と基礎を押さえます。他の RDBMS との立ち位置・強み弱み、PostgreSQL 固有の階層構造 (クラスタ → データベース → スキーマ → テーブル)、主要データ型、psql の使い方、SQL の基本、トランザクションといった「読み進める前提となる共通言語」を整える章です。最後に SQL を投げてから結果が返るまでの大まかな流れも見ます。
他 RDBMS との比較階層構造 (cluster/database/schema)主要データ型psql の基本主要 SQL コマンドトランザクションの基本クエリ実行の 5 ステージ概要
SECTION 01

PostgreSQL の基礎

この章ではまず、PostgreSQL を本格的に深掘りする前に押さえておきたい基礎をおさらいします。「PostgreSQL とは何か」「どんな立ち位置の DB か」「どんな階層構造で、どんなデータ型があり、どうやって操作するか」「トランザクションとは」といった共通言語をここで揃え、次章以降の内部解剖に備えます。すでに知っている内容は読み飛ばしてもらって構いません。

PostgreSQL(ポストグレス、または PG)は、1986 年にカリフォルニア大学バークレー校で生まれたオープンソースのオブジェクト関係データベース管理システム (ORDBMS) です。単なる RDBMS ではなく、ユーザー定義型・継承・複雑なクエリ・JSON ネイティブサポートなど、オブジェクト指向の概念を取り込んでいるのが名前の由来 (Post-Ingres) です。

まずは PostgreSQL が他の RDBMS とどう違うのか、業界での立ち位置から見ていきます。

主要 RDBMS との比較

DB分類強み弱み
PostgreSQL
OSS / Object-Relational機能の豊富さ・標準 SQL 準拠・拡張性スキーマレス用途では NoSQL に劣る
MySQL
OSS (Oracle 所有)シンプルさ・読み取り速度・運用ナレッジ機能セットが限定的・ストレージエンジン依存
Oracle DB
商用 (高額)エンタープライズ機能・サポート・成熟度コスト・複雑さ・ベンダーロックイン
SQLite
OSS / 組込み組込み・軽量・ファイル 1 つ同時書込が苦手・大規模不向き

PostgreSQL が選ばれる場面は明確です。「複雑なクエリ・データ整合性・拡張性」が 重要なシステム——金融・地理情報・大規模 EC・分析基盤など。逆に、シンプルな KVS で済むキャッシュ層や、 書込が極端に少ない組込み用途では、別の選択肢のほうが適しています。

採用企業の例

Instagram
本番 DB のメイン
Spotify
バックエンドの中核
Apple
iCloud の一部
Reddit
長年の本番 DB
TripAdvisor
メインデータストア
Mastercard
金融取引
楽天
一部サービス
クックパッド
メイン DB

PostgreSQL の階層構造 — クラスタ / データベース / スキーマ / テーブル

ここから先を読み進めるにあたって、PostgreSQL の「データの入れ物の階層」を最初に押さえます。本記事で「データベース」「スキーマ」といった用語が頻繁に出てきますが、これらは MySQL や Oracle と意味が少し違います。

① CLUSTER(= 1 つの PostgreSQL サーバ・1 つの postmaster)② Database: myapp③ Schema: publicusers (table)orders (table)idx_users_emailget_total(...)③ Schema: auditevent_logaccess_log② Database: warehouse③ Schema: publicsales_summary③ Schema: tenant_aordersproducts

階層は3 層です。

① クラスタ (Cluster)
1 つの postmaster プロセスが管理する DB 群の集まり。物理的には 1 つの PostgreSQL サーバ。initdb で初期化される単位で、データは PGDATA/ ディレクトリに置かれる。
他 DB の「インスタンス」とほぼ同義。
② データベース (Database)
クラスタの中に複数作れる独立した DB 空間。接続時に -d で 1 つを選ぶ。別 DB の中身は同じ SQL では参照不可。CREATE DATABASE で増やせる。
MySQL の「データベース」は PostgreSQL では「スキーマ」に近い概念なので注意。
③ スキーマ (Schema)
1 つのデータベース内の名前空間 (namespace)。テーブル・ビュー・関数などのオブジェクトを論理的にグルーピングする。デフォルトは public
マルチテナント分離、アプリ層分離、拡張機能の隔離などに活用される。
オブジェクト
スキーマ内に作られる実体。テーブル / インデックス / ビュー / 関数 / シーケンス / 型など多数。
一番触る単位。

スキーマ修飾は schema_name.table_name と書きます (例: audit.event_log)。明示しなければ search_path 設定 (デフォルト "$user", public) に従って解決されます。

ロール — ユーザーもグループも、すべて「ロール」

PostgreSQL のアクセス制御は「ロール」という単位で行われます。他の DB と違って、PostgreSQL ではユーザーもグループも区別せずすべて「ロール」で扱います。区別は属性の違いだけです。

LOGIN 属性あり = ユーザー
psql やアプリから接続できるロール。CREATE USERCREATE ROLE ... LOGIN のショートカット。
LOGIN 属性なし = グループ
ログインはできないが、権限の入れ物として使う。CREATE GROUPCREATE ROLE ... NOLOGIN のショートカット。
-- ① ユーザー (ログイン可能なロール)
CREATE ROLE alice WITH LOGIN PASSWORD 'xxx';

-- ② グループ (ログイン不可、権限の束)
CREATE ROLE app_team NOLOGIN;
GRANT SELECT, INSERT, UPDATE ON orders TO app_team;

-- ③ alice を app_team のメンバーに
GRANT app_team TO alice;
-- → alice は app_team の権限を継承して使える

主要データ型 — まず押さえるべき型

PostgreSQL は SQL 標準型に加えて、独自の強力な型を多数持っています。日常的に使う主要なものを分類別にまとめました。

数値型
smallint2 byte (-32768 〜 32767)
integer / int4 byte (約 ±21 億)。最頻出
bigint / int88 byte。サロゲートキーは普通こちら
numeric(p, s) / decimal可変精度。金額計算は必ずこれ (float は誤差が出る)
real / double precision4 / 8 byte の浮動小数点。誤差あり
文字列型
text可変長。本番の標準。長さ制限なし
varchar(n)n 文字までの可変長。本質的に text と同じ
char(n)固定長 (足りない分を空白埋め)。ほぼ使わない
日時型
timestamptz本番標準。タイムゾーン付き。UTC で保存・取り出し時に変換
timestampTZ なし。曖昧さの元なので非推奨
date日付のみ (時刻なし)
time / timetz時刻のみ。あまり使わない
interval期間。"3 days 2 hours" のような値が入る
ブール / バイナリ
booleantrue / false / null
byteaバイナリデータ (画像など)
uuid128bit のユニーク ID。gen_random_uuid() で生成
PostgreSQL 特有の強力な型
jsonbバイナリ JSON。インデックス可、検索高速。JSON は基本これ
jsonテキスト JSON。jsonb の方が良いケースが多い
配列 (例: int[])任意の型を配列に。tags text[] のように
enumCREATE TYPE status AS ENUM (...) で独自列挙型
範囲型 (int4range / tstzrange)値の範囲 (期間予約システムなど)
inet / cidrIP アドレス / ネットワーク
point / polygon / geometry (PostGIS)地理空間データ

psql の基本 — 接続とメタコマンド

psql は PostgreSQL の標準対話クライアントです。SQL を実行するだけでなく、独自のメタコマンド (バックスラッシュコマンド) で DB の状態を素早く確認できる、本番調査の最強の道具です。

# === 接続方法 ===
# 個別オプションで
psql -h db.example.com -p 5432 -U alice -d myapp

# 接続文字列 (URI) で
psql "postgresql://alice:xxx@db.example.com:5432/myapp"
psql "postgresql://alice@db.example.com/myapp?sslmode=require"

# 環境変数でも可
export PGHOST=db.example.com PGUSER=alice PGDATABASE=myapp
psql

# === よく使うメタコマンド ===
\?              -- メタコマンド一覧 (ヘルプ)
\h CREATE TABLE -- SQL コマンドの構文ヘルプ
\q              -- psql 終了

# 一覧系
\l              -- 全 DB 一覧
\du             -- 全ロール一覧
\dn             -- 全スキーマ一覧
\dt             -- 現在スキーマのテーブル一覧
\dt public.*    -- public スキーマの全テーブル
\di             -- インデックス一覧
\dv             -- ビュー一覧
\df             -- 関数一覧

# 詳細系
\d users        -- テーブル定義 (列・index・FK 等)
\d+ users       -- さらに詳しい情報 (サイズ・コメント等)
\dt+            -- テーブル一覧 + サイズ情報
\du+ alice      -- ロールの詳細属性

# 設定 / 接続
\c warehouse    -- 別 DB に接続切替
\conninfo       -- 現在の接続情報
\set            -- psql 変数一覧
\timing on      -- クエリ所要時間を表示
\x              -- 拡張表示 (1 カラム 1 行) 切替

# 出力先 / ファイル実行
\o /tmp/out.txt -- 出力をファイルへ
\i schema.sql   -- SQL ファイルを実行
\copy users TO '/tmp/users.csv' CSV HEADER
\copy users FROM '/tmp/users.csv' CSV HEADER

覚えるべき必須メタコマンド: \d (オブジェクト詳細)、\dt (テーブル一覧)、\du (ロール一覧)、\l (DB 一覧)、\timing on (時間計測)、\x (拡張表示)。これだけで本番調査の 80% が回ります。

主要 SQL コマンド一覧 — DDL / DML / TCL

SQL コマンドは大きく 3 種類に分類されます。これからの章でも頻出する用語なので、ここで整理しておきます。

DDL (Data Definition Language) — 構造を定義
CREATE TABLEテーブルを作る
ALTER TABLEテーブル定義を変更する (列追加・型変更・制約追加など)
DROP TABLEテーブルを削除する
CREATE INDEXインデックスを作る
CREATE SCHEMA / DATABASEスキーマ / DB を作る
TRUNCATE TABLE全行高速削除 (DDL 扱い、ロールバック可能)
DML (Data Manipulation Language) — データを操作
SELECTデータを取得する。最頻出
INSERT行を追加する
UPDATE行を更新する
DELETE行を削除する
COPY大量データを高速入出力する (バッチに必須)
MERGE / UPSERT (ON CONFLICT)存在すれば更新、なければ挿入
TCL (Transaction Control Language) — トランザクション制御
BEGIN / START TRANSACTIONトランザクション開始
COMMIT変更を確定
ROLLBACK変更を取り消し
SAVEPOINTトランザクション内に戻り点を作る
SET TRANSACTION分離レベル等を設定
DCL (Data Control Language) — 権限制御
GRANT権限を付与
REVOKE権限を剥奪

トランザクションの基本 — ACID と BEGIN / COMMIT / ROLLBACK

トランザクションは、複数の SQL 文を「全部成功するか、全部なかったことにする」 1 つの単位として扱う仕組みです。本番運用で最も基本的かつ重要な概念のひとつ。

PostgreSQL を含むリレーショナル DB のトランザクションは、ACID の 4 性質を満たします。

AAtomicity (原子性)トランザクション内の SQL は「全部実行 or 全部取り消し」。途中で止まることはない。
CConsistency (一貫性)制約 (PK / FK / CHECK) を破る変更はコミットされない。整合性が保たれる。
IIsolation (分離性)並行する他のトランザクションの中途半端な状態は見えない。分離レベルで制御 (Section 24 で深掘り)。
DDurability (永続性)COMMIT した変更はクラッシュしても失われない。WAL がこれを保証 (Section 12 で深掘り)。

基本的な書き方は次の通りです。

-- ① 普通のトランザクション
BEGIN;
  UPDATE accounts SET balance = balance - 100 WHERE id = 'alice';
  UPDATE accounts SET balance = balance + 100 WHERE id = 'bob';
COMMIT;
-- 両方成功してから確定。途中エラーなら何も変わらない

-- ② 失敗時の取消
BEGIN;
  UPDATE orders SET status = 'shipped' WHERE id = 1;
  -- ↑ ここでエラー or 「やっぱり取消したい」と思ったら
ROLLBACK;
-- → 何も変わらなかったことになる

-- ③ 自動コミット (BEGIN なしの場合)
UPDATE accounts SET balance = balance - 100 WHERE id = 'alice';
-- ↑ これ単体で 1 トランザクションとして即コミットされる
-- (psql のデフォルト挙動。明示的に BEGIN しなくても整合性は保たれる)

-- ④ 安全な実験 (本番で危険な UPDATE を試したい時)
BEGIN;
  UPDATE users SET deleted_at = now() WHERE created_at < '2020-01-01';
  SELECT count(*) FROM users WHERE deleted_at IS NOT NULL;
  -- ↑ 影響件数を確認
ROLLBACK;
-- → 結果だけ見て、本当は何もしなかったことにできる
この記事のゴール:初心者から中級のエンジニアが「本番運用で起きる問題の 9 割を自力で解決できる」状態を目指します。 ここまで押さえた基礎の上に、MVCC・WAL・実行計画・インデックスといった、Web 上の入門記事では深く触れない内部の仕組みを 徹底的に解説していきます。
SECTION 02

クエリが実行されるまで

本章では、SQL を投げてから結果が返ってくるまでに PostgreSQL の内部で起きていることを、5 つのステージとして俯瞰します。

私たちは普段「SELECT を投げる → データが返る」というように、SQL の入出力だけを意識して仕事をしています。しかし PostgreSQL の内部では、その 1 行の SQL に対して複数のサブシステムが順番にバトンを渡しながら処理を進めるパイプラインが動いています。具体的には Parser → Rewriter → Planner → Executor → Output という 5 段階で、それぞれが「SQL を構文木に変える」「ビューやルールを展開する」「最適な実行計画を選ぶ」「実際にデータを取りに行く」「結果をクライアントに返す」という別々の役割を担っています。

この 5 ステージの全体像を頭に入れておくと、後続の章で扱う EXPLAIN の読み方、クエリチューニング、パフォーマンス問題の切り分けが圧倒的にスムーズになります。「クエリが遅い時、どのステージが時間を食っているのか」「EXPLAIN が表示している計画は、どの段階の結果なのか」が見えるようになるためです。本章ではまず各ステージの役割を最小限で押さえ、所要時間の目安を整理します。詳細は G4 (15-17 章) で深掘りします。

クエリ実行の 5 ステージ

1. Parser1ms 未満2. Rewriter1ms 未満3. Planner数 ms 〜数十 ms4. Executorクエリの主時間5. Outputデータ量次第← SQL がクライアントから送られて、結果が戻るまで

各ステージの役割

1ParserSQL 文字列を構文解析して構文木に変換
2RewriterVIEW・ルールを実テーブルに展開
3Planner可能な実行計画を生成し、コストが最小のものを選ぶ
4Executorプランに従ってデータを取得・加工
5Output結果をクライアントへネットワーク経由で返す

押さえるべきポイントは Planner (3 番目) です。 ここで「Seq Scan する? Index Scan する? どの結合順がいい?」を判断しています。 EXPLAIN で見えるのは Planner の出力で、本記事の Section 09〜11 で深掘りします。

「クエリが遅い」と感じたら:① まず Planner が選んだプランが妥当か (EXPLAIN)、② Executor で実際にどれだけ時間が かかったか (EXPLAIN ANALYZE)、③ I/O ボトルネックか CPU ボトルネックか (pg_stat_*) の順で切り分けます。これが本記事を通じて何度も使う診断パターンです。

ここまでが無料公開部分です。次のセクションからは、これらの仕組みを実際に観察し、操作し、調整する方法を プレミアム会員向けに徹底解説していきます。

2
GROUP 2Section 03 — 08
アーキテクチャ
「postgres プロセスが何個も動いているのは何故?」「shared_buffers って結局どこにあって何をしているの?」を解決する章。Postmaster がどう起動して子プロセスを管理しているか、Backend / Background Worker / Auxiliary Process のそれぞれが何を担当するか、どんなメモリ領域が共有されているか、そしてそれらの挙動を制御する設定ファイルの全体像までを扱います。
プロセスモデル全体PostmasterBackend 内部Background プロセスメモリ構造設定ファイル 4 種
SECTION 03

プロセスモデル全体像

本章では、PostgreSQL のプロセスモデル全体像について学んでいきます。「PostgreSQL を起動した時に、内部で何が動いているのか」を俯瞰し、後続の章で各プロセスを詳しく見ていくための土台を作ります。

PostgreSQL のアーキテクチャ最大の特徴は マルチプロセスモデル を採用している点にあります。これは、クライアントが PostgreSQL に接続するたびに、OS 上に「新しいプロセスを 1 つ」フォークして割り当てる方式です。たとえば 100 人が同時に接続すれば、サーバ上には 100 個の postgres プロセスが並んで存在することになります。ps コマンドで観察すると、何個も postgres という名前のプロセスが並ぶのはこのためです。

対照的に、MySQL や Oracle はマルチスレッドモデルを採用しており、接続が増えてもプロセスは 1 つのまま、その中でスレッドだけが増えていきます。どちらにも一長一短があり、PostgreSQL がプロセス方式を選んだ理由 (堅牢性とクラッシュ耐性) と、その代償 (接続オーバーヘッドの大きさ) は、後続の接続プーリング章まで一貫して影響してきます。本章ではまず両者の違いを比較し、続いて PostgreSQL の典型的なプロセスツリー、プロセス間の通信手段までを順に押さえます。

マルチプロセスとマルチスレッドの比較

マルチプロセス (PostgreSQL)
◯ メリット
・1 プロセスがクラッシュしても他に影響しない
・OS の堅牢な分離機構を活用
・拡張機能の不具合に強い
・PostMortem (gdb 等) で個別調査が容易

× デメリット
・接続毎にメモリ消費 (数 MB〜数十 MB)
・接続数増大時のオーバーヘッド大
・PgBouncer 等の接続プーリングが必須に
・コンテキストスイッチがやや高い
マルチスレッド (MySQL)
◯ メリット
・接続毎のメモリ消費が小さい
・接続確立が高速
・コンテキストスイッチが軽い

× デメリット
・1 スレッドの不具合が全体に波及
・スレッド間競合のデバッグが難しい
・グローバル状態の管理が複雑
・OS のメモリ保護の恩恵が薄い

PostgreSQL の全体プロセスツリー (鳥瞰図)

Postmaster(親プロセス)常駐バックグラウンドプロセスCheckpointerBG WriterWAL WriterArchiverAutovacLauncherLogical RepLauncherLogger必要に応じて起動するプロセスStartup(復旧時)AutovacWorker × NBackend× 接続数WAL Sender× StandbyWAL Receiver(Standby)Apply Worker× SubscriberCustom BGWorker共有メモリ (全プロセスがアクセス)SharedBuffersWALBufferCLOGMultiXactLockManagerStats(PG 15+)SubTrans /ProcArrayディスク: base/ (heap, index) + pg_wal/ + global/ + アーカイブ先

図の4 層を順に押さえてください: ① 一番上に親の Postmaster、② 起動時に立ち上がる常駐バックグラウンド、③ 必要に応じて fork される動的プロセス、 ④ 全プロセスが共有する共有メモリと、その下にディスク。この階層構造を頭に入れておくと、後の章で出てくる細かい話が全部繋がります

プロセス間通信の手段

共有メモリ (System V / POSIX)Shared Buffers・WAL Buffer・CLOG など、データの実体を共有
シグナル (SIGHUP / SIGTERM / SIGUSR1 等)Postmaster → 子プロセス、子プロセス → Postmaster の通知
パイプクライアント接続のソケット転送など
ファイルpg_wal/, pg_xact/ などのディスクファイルを介した状態共有
sinval メッセージキューカタログキャッシュ無効化を全プロセスに通知
NOTIFY/LISTENクライアント向けのアプリレベル通知 (pg_notify)

ユースケース別プロセス動作シミュレータ

ここまでで「どんなプロセスが存在するか」は分かりました。次は「それらが実際の処理ごとにどう連携して動くか」を観察します。下のタブで代表的なユースケースを選ぶと、そのシナリオで動くプロセスが点灯し、データの流れと処理ステップが見えます。

SELECT (読み取り)
SELECT クエリが投げられた時、Backend が Shared Buffers を参照し、必要ならディスクからページを読み込んで結果を返すまでの流れ。
SHARED MEMORYDISKClientpsql / アプリPostmaster親プロセスBackend1 接続 1 プロセスShared BuffersページキャッシュCheckpointerBG WriterWAL Buffer変更ログ一時保管WAL WriterWAL を WAL Files へ flushAutovac Launcher掃除担当をスケジュールAutovac Workerデッドタプルを回収WAL SenderStandby へストリーム送信Data Filesテーブル / index 本体WAL Filespg_wal/ (耐障害ログ)Standby Server読み取りレプリカ1234
1クライアントが Backend に SELECT 文を送信します。
2Backend は Shared Buffers (メモリキャッシュ) を検索。必要なページがキャッシュにあれば即座に返ります (キャッシュヒット)。
3キャッシュになければ Data Files からページを読み込み、Shared Buffers に載せます (キャッシュミス → ディスク I/O 発生)。
4Backend が結果セットをクライアントに返却します。
本番でプロセスを観察:ps auxf | grep postgres で全プロセスツリーが見えます。SELECT * FROM pg_stat_activity で Backend と Background プロセスの状態が分かります。 まずは自分の環境で何が動いているかを観察するのが、アーキテクチャ理解の最良の方法です。
後の章への橋渡し:Section 04 では Postmaster と起動シーケンスを、05 では Backend プロセス内部を、06 では全バックグラウンドプロセスを、07 ではメモリとファイルレイアウトを、それぞれ深掘りしていきます。
SECTION 04

Postmaster と起動シーケンス

本章では、PostgreSQL のすべてのプロセスを束ねる司令塔である Postmaster と、その起動シーケンスについて学んでいきます。

Postmaster は、PostgreSQL クラスタ全体の親プロセスです。サーバを起動した際に、systemd や init から最初に起こされる実体がこの Postmaster で、以降の Checkpointer や WAL Writer、Autovacuum Launcher、そしてクライアント接続を担当する Backend プロセスといった子プロセスは、すべてこの Postmaster から派生 (fork) して生まれます。プロセスツリーで言えば最上位、つまり PostgreSQL の大元に位置するプロセスです。

ここで重要なのは、Postmaster 自身はクエリを実行しないという点です。Postmaster の仕事は次の 4 つに集約されます。① 子プロセスの起動、② 死亡監視と再起動、③ シグナルの中継、④ クライアント接続の受付と Backend プロセスの fork。クエリの実行は子プロセス側の責任で、Postmaster はあくまで「人事と総務」に専念しています。本章ではこの 4 つの責務と、サーバ起動時に何がどの順番で初期化されるか、そしてクラッシュからの自動復旧やシャットダウンの仕組みを順に見ていきます。

Postmaster の 4 つの責務

子プロセスの起動
起動時に常駐バックグラウンドプロセス (Checkpointer・WAL Writer・Autovacuum Launcher など) を順番に fork
死亡監視と再起動
SIGCHLD で子プロセスの異常終了を検知。クリティカルな子 (Checkpointer 等) が死ぬとクラスタ全体を再起動
シグナル中継
クライアントや systemd から SIGHUP (設定再読込) / SIGTERM (停止) を受けると、関連子プロセスに伝播
クライアント接続の受付と fork
5432 ポートで listen → 接続を受けたら fork して Backend プロセスを生成。Backend は認証・クエリ実行を担当

起動シーケンス

1systemd / init が postgres バイナリを起動これが Postmaster になる
2postgresql.conf を読み込み設定値を内部構造体に格納
3共有メモリの確保shared_buffers / wal_buffers / CLOG など。OS から System V/POSIX shared memory を取得
4pg_hba.conf を読み込み認証ルールを準備
5Startup プロセス fork前回が異常終了していたなら WAL からのクラッシュ復旧 (Crash Recovery) を実行
6復旧完了を待機Startup が完了するまで Backend 受付は開始しない
7常駐バックグラウンドプロセスを forkCheckpointer → BG Writer → WAL Writer → Archiver → Autovacuum Launcher → Logical Rep Launcher → Logger の順
85432 ポートを listen 開始これでクライアント接続を受付可能に
9クライアント接続が来たら forkBackend プロセスを生成 → 認証 → クエリ実行
10監督ループに入るSIGCHLD・SIGHUP・SIGTERM を待ち受け、永遠に

クラッシュ復旧 (Crash Recovery)

異常終了 (kill -9 / OS パニック等) で再起動した時、Postmaster はStartup プロセスを起動して最後の Checkpoint 以降の WAL を全部リプレイします。

# 異常終了後の起動ログ例
LOG:  database system was interrupted
LOG:  database system was not properly shut down; automatic recovery in progress
LOG:  redo starts at 0/A1B2C000
LOG:  redo done at 0/A1F50000 system usage: CPU 1.23s/0.45u sec
LOG:  database system is ready to accept connections

# WAL を 4MB ぶんリプレイした、という意味。
# → checkpoint_timeout を短くしておけば復旧が速い

シャットダウンの 3 つのモード

Smart Shutdown
pg_ctl stop -m smart (デフォルト)
挙動: 既存セッションが終わるのを待つ。新規接続は受け付けない
場面: 計画停止。優しい挙動だが時間がかかる
Fast Shutdown
pg_ctl stop -m fast
挙動: 既存セッションを強制終了。Checkpoint 実行後に停止
場面: 通常のメンテナンス。一般的な選択
Immediate Shutdown
pg_ctl stop -m immediate
挙動: Checkpoint なしで即停止。再起動時にクラッシュ復旧
場面: 緊急のみ。データロスはないが再起動が遅くなる

主要なシグナルとその意味

SIGHUP外部から / pg_ctl reloadpostgresql.conf を再読込。子プロセスにも伝播
SIGINTpg_ctl stop -m fastFast Shutdown を開始
SIGTERMpg_ctl stop -m smart / systemdSmart Shutdown を開始
SIGQUITpg_ctl stop -m immediateImmediate Shutdown (即停止)
SIGCHLDOS から自動子プロセスが終了したことを Postmaster に通知
SIGUSR1プロセス間汎用通知 (バックグラウンドプロセス間連携)
Postmaster の異常終了は致命的:Postmaster が kill されると、全 Backend プロセスは「親なし子」になり、リソースリークの危険があります。 本番では kill -9 postmaster は絶対に避けてください。
観察コマンド:pg_ctl status -D /var/lib/postgresql/16/main で稼働状況、postmaster.pid ファイルで PID やソケット情報が読み取れます。
SECTION 05

バックエンドプロセス内部

本章では、PostgreSQL でクエリを実際に実行する役割を担う Backend プロセスの内部構造について学んでいきます。

Backend プロセスは、クライアント 1 接続につき 1 つフォークされる、クエリ実行担当のプロセスです。たとえば psql でログインしたり、Web アプリが connection pool 経由で DB に接続した瞬間、Postmaster は裏で 1 つ Backend プロセスを fork し、以降そのプロセスがクライアントとの 1 対 1 のやり取りを担当します。接続が切れるとプロセスも終了します。ps で見える「postgres: user db host idle」のような行が、まさにこれです。

Backend プロセス自体は単一のプロセスですが、その内部にはSQL を受け取って結果を返すまでの一連の処理を分担するサブシステムが組み込まれています。具体的には、SQL 文を解析する Parser、意味解析と書き換えを行う Rewriter、最適な実行計画を選ぶ Planner、そして実際にデータを取りに行く Executor の 4 段構成です。本章ではこの内部構造を順に追い、加えて Backend が確保するメモリ領域、ステートマシン (idle / active / idle in transaction など) の挙動までを扱います。

Backend プロセスのライフサイクル

forkPostmaster から fork認証pg_hba.conf チェックidleクエリ待ちactiveクエリ実行中idle in txnトランザクション中の待ちclose切断クエリ完了で idle に戻る

Backend 内部のサブシステム

Backend プロセスは、クエリを受けると4 つのサブシステムを順番に通します。 このパイプラインを正しく理解しないと、なぜ EXPLAIN がそういう計画を出すか、なぜプリペアドステートメントが速いか、といった話が腑に落ちません。 各サブシステムを 1 つずつ深掘りします (Section 15 でさらに詳しく)。

Backend Process 内部ParserSQL を構文木へRewriterVIEW・ルール展開Planner実行計画生成Executor実データ処理

① Parser — SQL を構文木に変える

クライアントから届いた SQL 文字列を抽象構文木 (AST) に変換するサブシステム。 単に「文字列 → ツリー構造」ですが、ここで発生するエラーは構文エラー (syntax error)として返ります。

仕事の内容
① 字句解析 (Lexer) — 「SELECT」「FROM」などのキーワードを識別
② 構文解析 (Parser) — yacc/bison で書かれた文法でツリー化
③ 構文チェック — カッコの対応、句の順序、予約語の使い方
④ 結果: RawStmt という構造体 (まだ意味は知らない)
例: SQL → 構文木
-- 入力 SQL
SELECT name FROM users WHERE id = 5;

-- Parser の出力 (概念的)
SelectStmt
  ├─ targetList: [ColumnRef("name")]
  ├─ fromClause: [RangeVar("users")]
  └─ whereClause:
       A_Expr "="
         ├─ ColumnRef("id")
         └─ A_Const(5)

-- この時点では:
-- ・users テーブルが存在するか知らない
-- ・id カラムが integer かも知らない
-- ・5 が int4 か int8 かも未確定
失敗パターン:ここでエラーが出るのは「SQL の書き方が間違っている時」だけ。テーブルやカラムが存在しないエラーは次の Analyzer/Rewriter で出ます。

② Analyzer / Rewriter — 意味を持たせて書き換える

Parser が出した「生のツリー」に意味づけを行い、VIEW やルールを展開するフェーズ。実体は parse_analyze + QueryRewriter の 2 段階に分かれます。

Analyzer (parse_analyze) の仕事
① カタログ参照 — テーブル・カラムが実在するか pg_class / pg_attribute を確認
② 型推論 — リテラルの型を確定 (例: 5 → integer)
③ 関数解決 — 同名関数の中からどれを呼ぶか決定 (オーバーロード解決)
④ 暗黙キャスト挿入 — 必要なら型変換ノードを挿入
⑤ 結果: Query 構造体 — 意味の確定したツリー
Rewriter の仕事
① VIEW の展開 — SELECT * FROM active_users を元 SELECT に置換
CREATE RULE で定義されたルールの適用
③ Row-Level Security (RLS) の WHERE 句を自動付加
SELECT FOR UPDATE 系のロック指定の正規化
このフェーズで出るエラー例:relation "foo" does not existcolumn "bar" does not existfunction f(integer) does not exist など。 これらは「構文は正しいが、DB の現状とマッチしない」エラーです。

③ Planner / Optimizer — 最適な実行計画を選ぶ

PostgreSQL の頭脳。同じ Query を実行する方法は無数にあるため、統計情報とコストモデルから最も速い計画を見つけ出します。 ここでの判断が悪いと、本来 0.1 秒で済むクエリが 10 秒かかったりします。

Planner の 5 ステップ
プリプロセス — 定数畳み込み、不要な JOIN の削除、サブクエリの展開
スキャン方法の候補列挙 — Seq Scan / Index Scan / Index Only Scan / Bitmap Scan
JOIN 順序の探索 — N テーブルなら最大 N! 通りの順序を評価 (Dynamic Programming or GEQO)
JOIN アルゴリズム選択 — Nested Loop / Hash Join / Merge Join のいずれか
コスト計算で最安を選択 — startup cost + run cost を random_page_cost 等のパラメータで評価
カギは統計情報

Planner の判断はすべて pg_statistic に蓄積された統計情報に依存しています。 ANALYZE が古いと「100 万行返ると思って Hash Join 選んだら実は 5 行だった」のように桁違いに外すことになります。

-- 統計が利用可能か確認
SELECT relname, n_live_tup, last_analyze, last_autoanalyze
FROM pg_stat_user_tables WHERE relname = 'orders';

-- 重要カラムは統計の解像度を上げる
ALTER TABLE orders ALTER COLUMN status SET STATISTICS 1000;
ANALYZE orders;

-- ヒストグラム を見る
SELECT * FROM pg_stats WHERE tablename = 'orders' AND attname = 'status';
Planner が苦手なケース:① 強い相関のあるカラム間の AND 条件 (pg_statistic は単独統計のみ)、 ② パラメータ化クエリで値依存の最適化が効きにくい、 ③ 大量 JOIN (≥12 テーブル) で GEQO の精度が落ちる。 対策: CREATE STATISTICS で多変量統計、または明示的なヒント拡張 (pg_hint_plan) を検討。

④ Executor — 計画を実データに対して実行する

Planner が決めたツリー (PlanNode のツリー) をVolcano モデルで実行する部分。 各ノードが「次の 1 行をくれ (next())」と親に呼ばれ、再帰的に子へ伝播 → 子が 1 行返す、を繰り返します。

主要な PlanNode の種類
Seq Scanテーブル全件スキャン (インデックス使わず)
Index Scanインデックスから 1 件ずつ取得 → ヒープ参照
Index Only Scanインデックス内の値だけで完結 (heap 参照スキップ)
Bitmap Heap/Index Scan大量の行を効率取得 (OR 条件などで有利)
Nested Loop外側ループ × 内側ループ。小さい × 小さい や Index 利用時に有利
Hash Join内側をハッシュ化してから外側を流す。大規模の =JOIN に強い
Merge Join両者ソート済みなら 1 パスでマージ。ORDER BY のキー一致時に強い
Sortwork_mem に収まれば quicksort、超えたら外部ソート
AggregateGROUP BY や集計関数 (sum / count) の処理
Gather / Gather MergeParallel Worker から結果を集める
Appendパーティション結合・UNION ALL
Limit指定件数で打ち切り
Volcano モデルの動き
-- SELECT name FROM users WHERE id > 5 ORDER BY name LIMIT 10;

Limit (10)
 └→ next() を 10 回呼ぶ
     └→ Sort (ORDER BY name)
         └→ 子から全行取って一気にソート
             └→ Index Scan (id > 5)
                 └→ Btree を順に辿って 1 件ずつ next() で返す

-- 各ノードは「次の 1 行を返す」だけのシンプルなインターフェース
-- これを組み合わせるだけで複雑な SQL が表現できる
Volcano の限界と JIT:関数呼び出しオーバーヘッドが行ごとに発生するため、近年はJIT コンパイル (PG 11+) で頻出ノードを実行時に機械語化する最適化が入っています。 重い分析クエリで効くため、デフォルトで JIT が有効です (jit_above_cost = 100000)。

まとめ — 1 クエリの流れ

クライアント → 文字列 "SELECT ..." → Backend
                                       │
                                  ┌────▼────┐
                                  │ Parser  │  → 構文木 (RawStmt)
                                  └────┬────┘
                                       ▼
                                  ┌─────────┐
                                  │Analyzer │  → 意味確定 (Query)
                                  │+Rewriter│  → VIEW/RLS 展開
                                  └────┬────┘
                                       ▼
                                  ┌─────────┐
                                  │ Planner │  → 最適計画 (PlannedStmt)
                                  └────┬────┘
                                       ▼
                                  ┌─────────┐
                                  │Executor │  → 実データ取得・処理
                                  └────┬────┘
                                       ▼
                              結果をクライアントへ返却

Backend が確保するメモリ領域

work_memデフォルト 4MBSort・Hash・Materialize 1 操作あたりの最大メモリ。複数操作なら倍数を消費
temp_buffersデフォルト 8MB一時テーブル用のローカルバッファ。セッション毎に独立
maintenance_work_memデフォルト 64MBVACUUM・CREATE INDEX 等の保守作業用
カタログキャッシュ不定 (リレーション数依存)pg_class・pg_attribute 等のメタデータをプロセス内にキャッシュ
プラン/クエリキャッシュ不定Prepared Statement の実行計画を保持

idle in transaction

idle in transaction は「BEGIN したまま COMMIT/ROLLBACK しないで何もしていない状態」。 これがあると、VACUUM が古いタプルを回収できないロックが保持されたままになり、本番障害の主要原因の 1 つです。

-- idle in transaction を発見
SELECT pid, usename, state, now() - state_change AS duration, query
FROM pg_stat_activity
WHERE state = 'idle in transaction'
ORDER BY duration DESC;

-- タイムアウトを設定 (本番では必須)
ALTER SYSTEM SET idle_in_transaction_session_timeout = '5min';
ALTER SYSTEM SET statement_timeout = '30s';
SELECT pg_reload_conf();

Backend のステートマシン (pg_stat_activity.state)

activeクエリ実行中。CPU/IO を消費している
idleクエリ待ち。コネクションは生きているが何もしていない
idle in transactionBEGIN 後・COMMIT 前で何もしていない (危険)
idle in transaction (aborted)トランザクションが失敗状態で ROLLBACK 待ち
fastpath function call高速関数呼び出し中 (まれ)
disabledtrack_activities = off の場合のみ
Prepared Statement の世界:Backend はPrepared Statement (準備済みクエリ) を内部に保持できます。同じプロセスで再実行すると Parser/Planner をスキップでき高速ですが、 PgBouncer の transaction モードでは保持されない罠があります (Section 37 参照)。
LISTEN/NOTIFY:Backend は LISTEN channel でクライアント間メッセージ通知を受け取れます。 簡易的な pub/sub として使えますが、メッセージは永続化されないので Kafka 等の代替にはなりません。
SECTION 06

バックグラウンドプロセス

本章では、PostgreSQL の裏側で常時動き続けているバックグラウンドプロセス群について学んでいきます。

バックグラウンドプロセスとは、クライアントの SQL とは無関係に PostgreSQL が勝手に動かしている裏方の常駐プロセスのことです。クエリを 1 つも投げていない状態でも、ps で見ると checkpointerautovacuum launcher など、複数の postgres: プロセスが並んでいるのが見えます。これらが各々「ディスクへの書き出し」「WAL ログの記録」「不要になった行の掃除」といった運用維持の仕事を分担して担当しており、DB が止まらず動き続けるための心臓部となっています。

本章ではこれらすべてのバックグラウンドプロセスを 1 つずつ取り上げ、「なぜそのプロセスが存在するか」「どのような動作をしているか」「本番でどんな問題を起こし得るか」を網羅的に解説します。各プロセスの役割を把握しておくと、本番運用中に「このプロセスが多すぎる」「このプロセスの動きが遅い」といった異常に気付けるようになり、トラブル時の原因特定が格段に早くなります。

1. Background Writer (bgwriter)

ROLE
Shared Buffers の汚れたページを少しずつディスクへ書き出す
PostgreSQL は性能のために、テーブルやインデックスのデータをいちいちディスクから読まず、メモリ上の Shared Buffers という共有キャッシュにいったん載せて高速化しています。UPDATE で行を書き換える時も、まずこのメモリ上のキャッシュを書き換え、ディスクへの反映は後回しにします。「書き換えたがまだディスクへ書き戻されていない」状態のページのことを dirty page (汚れページ) と呼びます。

dirty page を放置しておくとキャッシュは満杯になり、新しいデータをキャッシュに乗せたい Backend が「空きを作るため自分でディスクへ書き戻してから読み込む」という重い処理を発動する羽目になります。すると一瞬で数百ミリ秒のレイテンシスパイクが起きて、ユーザーから「たまにクエリが急に重い」という苦情に繋がります。

bgwriter はそうなる前に「使われていなさそうな dirty page を、少しずつ静かにディスクへ書き戻しておく」役目の先回りの掃除係です。200ms ごとに目を覚まし、LRU (Least Recently Used = 最近使われていない順) の末尾にあるページを最大 100 個まで書き出します。Checkpointer が定期的に「全 dirty page をまとめて一気に書く」のと違い、bgwriter は少しずつ穏やかに処理するので、I/O の波が立たず、クエリのレイテンシが安定するのが最大の利点です。
データフロー
Shared Buffers(RAM)bgwriter200ms 周期Data Files(Disk)読出書出LRU 末尾の dirty page を先回りでディスクへ移し、Backend の待ちを防ぐ
動作ステップ
1
200ms 周期で起動
2
Shared Buffers の LRU 末尾 (使われていない汚れページ) を最大 100 個書き出す
3
書き出したページは「クリーン」になり、Backend が再利用できる
4
また 200ms スリープ
注意点
bgwriter が間に合わないと「Backend 自身が書き出し」状態が増え、pg_stat_bgwriter.buffers_backend が増加。これが見えたら bgwriter_lru_maxpages を増やすか、shared_buffers を増やすのがセオリー。
関連パラメータ
bgwriter_delay = 200msbgwriter_lru_maxpages = 100bgwriter_lru_multiplier = 2.0bgwriter_flush_after = 512kB
観察方法
pg_stat_bgwriter (buffers_clean / buffers_backend / buffers_alloc)

2. Checkpointer

ROLE
Checkpoint 発動時に Shared Buffers の全 dirty page を一気にディスクへ同期
前章で見た WAL は「変更内容を追記し続けるログ」で、これがあるおかげで電源が落ちてもデータが守られます。ただし WAL は放っておくと永遠に増え続けるので、ある時点で「ここまでの変更は全部 Data Files (本体のテーブル) に反映済みです」と区切りを宣言し、それ以前の WAL を捨てられる状態にする必要があります。この区切りが Checkpoint (チェックポイント) です。

Checkpoint がないと、① WAL ファイルが pg_wal/ ディレクトリに無限に溜まってディスクを使い切る、② クラッシュ後の起動で「最初の WAL から最新まで全部リプレイ」するのに何時間もかかる、という致命的な問題が起きます。ゲームに例えるなら「オートセーブが一度も走らないまま遊び続けている」ような危険な状態です。

Checkpointer はこの保存を担当する常駐プロセスです。5 分経過 (checkpoint_timeout) または WAL が 1GB 溜まった (max_wal_size 到達) のどちらかが先に来た時に発動します。発動すると、その瞬間までに変更されていた全 dirty page をディスクに fsync (書き込み確定) して、WAL に「Checkpoint 完了」のマーカーを書き込みます。これ以降、それより古い WAL は捨てて構わない状態になります。

Checkpoint 発動時は I/O 量が一気に増えるので、checkpoint_completion_target を 0.9 にして書き出しを時間で分散する設定が本番では定石です。
データフロー
Shared Buffers全 dirty pageCheckpointer5min / 1GB で発動Data Filesfsync で永続化WAL FilesCheckpoint レコード送出fsync記録完了後、それ以前の WAL は削除可能になる
動作ステップ
1
checkpoint_timeout (5 分) か max_wal_size (1GB) のどちらかが先に達すると発動
2
全ての汚れページを fsync
3
完了したら新しい Checkpoint レコードを WAL に書く
4
それより古い WAL を削除可能に
注意点
「checkpoints_req が急に増えた」は max_wal_size を超えてしまっている兆候。checkpoint_completion_target = 0.9 で書き込みを 90% の時間に分散できるので、I/O スパイクを抑えられる。
関連パラメータ
checkpoint_timeout = 5minmax_wal_size = 1GBmin_wal_size = 80MBcheckpoint_completion_target = 0.9checkpoint_flush_after = 256kB
観察方法
pg_stat_bgwriter.checkpoints_timed (時間トリガ) / checkpoints_req (サイズトリガ)

3. WAL Writer

ROLE
WAL Buffer の内容を定期的にディスクへフラッシュする
PostgreSQL では COMMIT が完了した瞬間に「もうクラッシュしてもこのデータは失われない」と保証する必要があります。そのために、コミットの瞬間に WAL ログを必ずディスクに書き出し終わってから (fsync が完了してから) クライアントに成功を返します。

ここで問題になるのが、ディスク書き込み (fsync) は非常に遅い処理だということです。たとえば SSD でも数ミリ秒、HDD なら数十ミリ秒かかります。もし Backend がコミットのたびに自分でこの fsync をすべて行うと、書き込み中心のシステムでは応答時間が大幅に悪化します。

WAL Writer はこの問題を解決する常駐プロセスで、「Backend が fsync で待たされる前に、先回りで WAL Buffer (メモリ上の WAL 待避領域) の内容をディスクに流し込んでおく」役目を持ちます。200ms ごとに目を覚まし、まだディスクに書かれていない部分を fsync します。

これにより、Backend がコミット時に行う fsync は「すでに書き込まれた範囲を確定するだけ」になり、ほぼ待たずに済むようになります。さらに synchronous_commit = off を選べば、WAL Writer の書き出しすら待たずにコミット成功を返せるようになり、クラッシュ時のデータロスを許容する代わりに極限まで応答速度を上げられます (非同期コミットの仕組み)。
データフロー
WAL Buffer(RAM)WAL Writer200ms 周期WAL Filespg_wal/送出fsync事前書込でコミット時の Backend の待ちを短縮
動作ステップ
1
200ms 周期で起動
2
WAL Buffer 内のまだディスクへ書いていない部分を write()
3
wal_writer_flush_after (1MB) 単位で fsync
4
また 200ms スリープ。コミット時の Backend は、すでに書かれていない部分だけ fsync すれば良い
注意点
synchronous_commit = off にすると WAL Writer の書き出しを待たずにコミットが返るので超高速だが、クラッシュ時に直前数百ミリ秒のデータが消える可能性がある。金融系は absolutely NG、解析・ログ系では有効。
関連パラメータ
wal_writer_delay = 200mswal_writer_flush_after = 1MBsynchronous_commit = on/off/local/remote_write/remote_apply
観察方法
pg_stat_wal (wal_records / wal_bytes / wal_write_time / wal_sync_time)

4. Archiver

ROLE
満杯になった WAL ファイル (16MB ごと) を別保管庫へコピー
PostgreSQL のバックアップ手段の中で最も強力なのが PITR (Point-In-Time Recovery、任意時点復元) です。「3 時間前の状態にロールバックしたい」「事故が起きた瞬間の直前に戻したい」といった要求を、「フルバックアップ + その時点までの WAL を順に再生 (リプレイ)」することで実現します。

ところが WAL ファイルは Checkpoint 完了後に「もう要らない」と判定されて削除またはリサイクルされてしまいます。これでは PITR ができないので、削除される前に WAL を別の保管場所 (S3 / NFS / 別ディスクなど) へ退避させておく必要があります。これを担当するのが Archiver です。

仕組みは次の通りです。WAL Writer や Checkpointer が 16MB の WAL セグメントを書き終えると、PostgreSQL は pg_wal/archive_status/ に対応する .ready という小さなマーカーファイルを作ります。Archiver はこのディレクトリを 1 秒間隔で監視し、新しい .ready を見つけると、postgresql.conf で指定した archive_command (例: aws s3 cp %p s3://bucket/%f) を実行して該当 WAL ファイルを退避します。成功すると .ready.done にリネームし、その WAL は PostgreSQL に「もう削除して良い」と通知されます。

この仕組みが詰まると WAL が削除されず pg_wal/ ディレクトリが無限に肥大化し、最終的にディスク満杯で本番停止という事故になります。本番では pg_stat_archiver.last_failed_time の監視が必須です。
データフロー
pg_wal/.ready マーカーArchiver1 秒毎に監視ArchiveS3 / NFS / 別ディスク.done成功時にリネーム検出コピー完了PITR の基盤。失敗で pg_wal/ が肥大化する
動作ステップ
1
WAL Writer / Checkpointer が WAL ファイルを完成させる (16MB 単位)
2
Archiver が pg_wal/archive_status/ を 1 秒間隔で監視
3
.ready ファイルを見つけたら archive_command 実行
4
成功したら .done にリネーム、失敗なら次回再試行
注意点
archive_command が遅い・失敗続きだと pg_wal/ に WAL が溜まり続け、ディスク満杯で本番停止。pg_stat_archiver.last_failed_time を必ず監視せよ。
関連パラメータ
archive_mode = onarchive_command = 'aws s3 cp %p s3://bucket/wal/%f'archive_timeout = 0 (= 0 だと WAL 満杯まで待つ)archive_library = ... (PG 15+ の代替)
観察方法
pg_stat_archiver (archived_count / failed_count / last_failed_wal)

5. Autovacuum Launcher

ROLE
各 DB の Autovacuum Worker を起動するスケジューラ
前章 (VACUUM の章) で見たように、PostgreSQL の MVCC の副作用としてテーブルにはデッドタプル (もう参照されない古い行) が溜まり続けます。これを掃除するのが VACUUM ですが、何百ものテーブルを抱える本番 DB で運用者が毎晩 cron で VACUUM を打って回るのは現実的ではありません。

そこで PostgreSQL は自動で必要なタイミングを判定して VACUUM を起動する仕組みを内蔵しています。それが Autovacuum で、その全体を統括する司令塔が Autovacuum Launcher です。

ただし VACUUM 自体は重い処理なので、全テーブルを常に掃除するわけにはいきません。「どのテーブルが、今、掃除を必要としているか」を見極めて、必要な分だけ働かせるスケジューラの役目を Launcher が担います。

Launcher は autovacuum_naptime (デフォルト 1 分) ごとに目を覚まし、クラスタ内の各データベースを順に巡回します。テーブルごとに pg_stat_user_tables を確認し、① デッドタプル数が閾値を超えているか、② INSERT が増えすぎていないか、③ XID 年齢が古くなりすぎていないか、のいずれかが該当すれば Autovacuum Worker を fork して実際の掃除を任せます。

Launcher 自身は判断と起動だけを担当し、実際の VACUUM 作業はしません。同時稼働できる Worker の数は autovacuum_max_workers (デフォルト 3) で決まります。本番ではテーブル数に応じて 5〜10 まで増やすことが多いです。
データフロー
pg_stat_user_tablesデッドタプル数Autovac Launchernaptime 毎に巡回Autovac Worker閾値超え時 fork監視forkLauncher は判定と起動のみ。実際の掃除は Worker が担当
動作ステップ
1
autovacuum_naptime (1 分) ごとに起動
2
全 DB を順番に巡回
3
pg_stat_user_tables を見て「デッドタプル数 > 閾値」のテーブルを発見
4
Worker を fork
5
Launcher は次の DB へ
6
1 周終わったらまたスリープ
注意点
autovacuum_max_workers (3) を超えるテーブルが同時に閾値超えしていると、最後の方は次のサイクルまで待たされる → デッドタプルが溜まる。本番では 4〜6 まで増やすことが多い。
関連パラメータ
autovacuum = on (絶対 OFF にしない)autovacuum_naptime = 1minautovacuum_max_workers = 3autovacuum_vacuum_threshold = 50autovacuum_vacuum_scale_factor = 0.2
観察方法
pg_stat_user_tables (last_autovacuum / n_dead_tup)

6. Autovacuum Worker

ROLE
実際の VACUUM / ANALYZE を実行するワーカープロセス
Autovacuum Launcher が「このテーブルを掃除すべき」と判定した時、実際に VACUUM を実行する短命な作業員プロセスです。1 つの Worker が 1 つのテーブルを最初から最後まで担当して、終わったら消滅します。複数の Worker が並列に動くこともあり、別々のテーブルを同時に掃除できます。

Worker の仕事は内部的に 4 段階で進みます。まずヒープスキャンでテーブル本体を順次読み、デッドタプルの位置 (TID) を maintenance_work_mem 上に記録します。次にIndex 掃除として、そのテーブルの全インデックスを 1 つずつスキャンして該当エントリを削除します。続いてHeap クリーンでテーブル本体のページを掃除し、可視性マップ (VM) を更新します。最後に必要に応じて統計情報も更新します。

インデックスが多いと Index 掃除フェーズが長くなります。PG 13 以降は VACUUM PARALLEL N で複数インデックスを並列処理できるようになりました。

本番でよく問題になるのが、長時間トランザクションが走っているとデッドタプルが「まだ古いトランザクションから見えているかも」と判断されて回収できなくなる現象です。1 件の idle in transaction セッションがあるだけで全テーブルの掃除が止まることもあり、statement_timeoutidle_in_transaction_session_timeout の設定が Autovacuum がちゃんと進むかどうかにも直結します。
データフロー
起動ヒープスキャンTID 記録Index 掃除エントリ削除Heap クリーンVM 更新統計更新ANALYZE1 回の VACUUM は 4 段階。Index 段階がもっとも時間を食う
動作ステップ
1
Launcher から DB と対象テーブルを渡されて起動
2
テーブル全体をスキャンしてデッドタプル位置を記録
3
関連インデックスを掃除
4
ヒープページを掃除
5
ANALYZE 必要なら統計更新
6
完了して終了
注意点
長時間トランザクション (idle in transaction) があると VACUUM が「古いタプルが本当にゴミか」を判断できず回収不可。statement_timeout / idle_in_transaction_session_timeout を本番では必ず設定すべし。
関連パラメータ
autovacuum_vacuum_cost_limit = 200autovacuum_vacuum_cost_delay = 2msautovacuum_vacuum_insert_scale_factor = 0.2 (PG 13+)
観察方法
pg_stat_progress_vacuum (進捗) / pg_stat_user_tables.last_autovacuum

7. Logical Replication Launcher

ROLE
論理レプリの Apply Worker を起動するスケジューラ (PG 10+)
PostgreSQL 10 以降で正式導入された論理レプリケーションは、「テーブル単位で別の DB に変更を流す」という柔軟なレプリ方式です。Subscription (購読) を作成すると、そのテーブル分の変更を継続的に受信して自分の DB に適用する Apply Worker が裏で常駐します。

実運用では複数の Subscription が同時に動いていることが多く (たとえばテーブルごとに別 Subscription を作って受信先を変える)、これらをまとめて管理する司令塔が必要になります。それが Logical Replication Launcher です。Apply Worker をいきなり全部勝手に起動させると管理が混乱するので、Launcher が中央集権的に「どの Subscription にどの Worker を割り当てるか」を判定します。

Launcher は PG 起動と同時に常駐し、pg_subscription ビューを定期的に確認します。有効化されているのにまだ Apply Worker が起動していない Subscription を見つけると、Worker を fork して起動します。Apply Worker が異常終了した場合の自動再起動も担当します。

Subscription の数が多い時は max_logical_replication_workers (デフォルト 4) の上限に注意が必要です。これを超える Subscription を作ろうとすると、起動できない Subscription が出てきます。Subscription を増やす時は max_worker_processes 全体も合わせて増やしておく必要があります。
データフロー
pg_subscription有効 Sub を列挙Logical Rep LauncherPG 起動時常駐Apply WorkerSub 毎に fork監視forkSubscription 1 つにつき Apply Worker 1 つを起動
動作ステップ
1
PG 起動時または CREATE SUBSCRIPTION 時に発動
2
pg_subscription を読み、有効な Subscription を列挙
3
未起動の Subscription に対して Apply Worker を fork
4
既存 Worker が死んだら再起動
5
監督ループへ
注意点
max_logical_replication_workers (4) を超える Subscription を作ろうとすると、最後の方が起動できずに停止状態に。Subscription を増やすときは max_worker_processes 全体も合わせて増やす必要あり。
関連パラメータ
max_logical_replication_workers = 4max_sync_workers_per_subscription = 2
観察方法
pg_stat_subscription (subscribed Worker の数と状態)

8. Logical Replication Apply Worker

ROLE
Subscriber 側で論理メッセージを受け取り、SQL として実行する
論理レプリケーションの「実際にデータを反映する係」。Subscriber 側で常駐し、Publisher (Primary) から流れてくる論理メッセージを受信して、自分の DB で SQL として再実行することで同期を取ります。

ここで物理レプリケーション (前章で扱った Streaming Replication) との違いをはっきりさせておきます。物理レプリは「Primary の WAL バイト列をそのままコピーして Standby で再生」する低レベルな方式で、Standby は Primary と物理的に完全に同じ状態になります。同じ PostgreSQL バージョン同士でしか動かず、全テーブル一律にコピーされます。

それに対して論理レプリは Apply Worker が Publisher から「users テーブルの id=5 に Taro という名前を INSERT」のような論理的に意味のあるメッセージを受け取り、それを自分の DB で SQL として実行するという方式です。これにより、① PG バージョンが違う DB に送れる、② 特定のテーブルだけ送れる、③ Subscriber 側でも書き込みができる、④ 異なるスキーマへの変換も可能、といった柔軟性が得られます。

一方で SQL として再実行するという仕組み上、テーブル構造が違うと apply エラーが起き、そこで同期が止まってしまうリスクもあります。本番運用では pg_stat_subscriptionlast_msg_send_timepg_subscription_rel.srsubstate を継続監視するのが必要です。
データフロー
PublisherPrimary 側Apply WorkerSubscriber 側で常駐Subscriber DB適用先テーブルメッセージSQL 実行物理レプリと違い、行レベルの「変更の意味」を流す
動作ステップ
1
Publisher へ接続し、レプリスロット経由でメッセージストリームを受信
2
各メッセージ (INSERT/UPDATE/DELETE) を SQL に変換
3
自 DB で実行
4
commit LSN を Publisher へ報告
5
ストリーム継続
注意点
Subscriber 側のテーブル構造が違うと apply エラーで停止。pg_subscription_rel.srsubstate が r (ready) でなくなったら要調査。
関連パラメータ
streaming = on (PG 14+ で in-progress txn を即時適用)binary = true (バイナリ高速)two_phase = true (PG 15+)
観察方法
pg_stat_subscription.received_lsn / latest_end_lsn / last_msg_send_time

9. WAL Sender (walsender)

ROLE
Streaming Replication で WAL を Standby / Subscriber へ送信
Streaming Replication (物理レプリ) でも論理レプリでも、Primary 側で発生した変更を別サーバに届ける送信担当が必要です。それが WAL Sender (walsender) で、Subscriber 1 接続につき 1 プロセスとして常駐します。

たとえば「Standby を 2 台立てて、論理レプリの Subscriber も 1 つ用意した」場合、Primary 側には walsender が 3 個動いていることになります。ps コマンドで postgres: walsender ... という表示で見えます。

Standby または Subscriber が Primary に接続した瞬間、Postmaster は新しい walsender を fork します。walsender は接続が切れるまで生き続け、pg_wal/ 配下の新しい WAL レコードを順次読み取り、TCP ストリームで Subscriber に逐次送信し続けます。物理レプリならバイト列をそのまま、論理レプリなら pgoutput で論理メッセージに変換してから送ります。

送信進捗の管理にはレプリケーションスロットという仕組みが使われます。Subscriber が「ここまで受信したよ」と ACK を返すと、walsender はスロットの restart_lsn を更新します。これが Primary 側にとって「この位置以前の WAL はもう削除して良い」というマーカーになります。

本番で頻発するトラブルは、Subscriber が長時間切断されたままスロットを残すと、Primary 側の WAL が永遠に削除されずにディスクが溢れることです。max_slot_wal_keep_size (PG 13+) で上限を設定するのが安全策です。同時稼働数は max_wal_senders (デフォルト 10) で制限されます。
データフロー
Replication Slot進捗管理 (restart_lsn)pg_wal/WAL ファイルWAL SenderSubscriber 毎に 1 個StandbyTCP 受信読出streamACK 更新Subscriber 遅延でスロットが古い WAL を保持し続ける
動作ステップ
1
Subscriber から接続を受けて起動
2
レプリスロットを取得 (進捗管理)
3
pg_wal/ から WAL を読み、TCP で逐次送信
4
物理レプリならバイト列をそのまま、論理レプリなら pgoutput で変換してから送信
5
Subscriber の ACK で restart_lsn を更新
注意点
Subscriber が遅延すると WAL が pg_wal/ に溜まり続ける。max_slot_wal_keep_size (PG 13+) を設定しないとディスク満杯リスク。pg_stat_replication で write_lag/flush_lag/replay_lag を必ず監視。
関連パラメータ
max_wal_senders = 10wal_keep_size = 0 (スロット使うなら 0 OK)max_slot_wal_keep_size = 50GB (PG 13+)
観察方法
pg_stat_replication (write_lag / flush_lag / replay_lag / sent_lsn / flush_lsn)

10. WAL Receiver (walreceiver)

ROLE
Standby 側で Primary から WAL を受信し、pg_wal/ に書き込む
Streaming Replication の受信側を担うプロセスです。Standby サーバ上で常駐し、Primary に接続して TCP ストリームで WAL を受信し、Standby 自身の pg_wal/ ディレクトリに書き込みます。Standby 1 台につき 1 プロセスです。

ここで設計上、特徴的なのは「受信と再生が別プロセスに分かれている」点です。WAL Receiver は受信と書き込みだけを担当し、実際にデータベースに反映する作業 (Redo) はしません。受信して pg_wal/ に書いた後、別プロセスである Startup プロセスに「ここまで来た」と通知します。Startup はその通知を受けて、新しく届いた範囲の WAL を順次再生してデータベースに反映します。

つまり Standby 上ではいつも 2 つのプロセス (Receiver と Startup) が連携してレプリを動かしている構造です。Receiver は受信担当、Startup は再生担当、と役割が分かれています。なぜ分けたかというと、受信と再生を分けて並列化することで、ネットワーク遅延と I/O 遅延が連鎖しないようにするためです。

本番で接続が切れた時は、wal_receiver_timeout (デフォルト 60 秒) 経過後に Receiver が異常を検知して再接続を試みます。長時間切断していると pg_stat_wal_receiver.statusstreaming → disconnected の遷移が見えます。設定ミス (primary_conninfo の typo、認証エラーなど) も Receiver のログから判別できます。
データフロー
Primary(WAL Sender)WAL ReceiverStandby 1 つ = 1 個pg_wal/Standby 側に書込Startupリプレイ担当stream書込通知Receiver と Startup が連携してレプリ再生を進める
動作ステップ
1
Primary に walsender を要求して接続
2
TCP ストリームで WAL を受信
3
pg_wal/ に書き込み
4
Startup プロセスに「ここまで来た」と通知
5
Primary に ACK 返信
6
受信継続
注意点
primary_conninfo の設定ミス・ネットワーク断・認証エラーで切断されると、しばらくして再接続を試みる (wal_receiver_timeout)。長時間切断は pg_stat_wal_receiver.status で確認可。
関連パラメータ
primary_conninfo = ...primary_slot_name = ...wal_receiver_timeout = 60swal_receiver_status_interval = 10s
観察方法
pg_stat_wal_receiver (status / written_lsn / flushed_lsn / latest_end_lsn)

11. Startup プロセス

ROLE
PG 起動時の WAL リプレイ / PITR 復旧 / Standby での継続的リプレイ
PostgreSQL が起動した瞬間、まず判定するのが「前回はちゃんと正常終了していたか」です。shutdown checkpoint が記録されていれば正常終了と判断して即座に通常モードへ。されていなければクラッシュからの起動と判断し、データの整合性を取り戻す必要があります。

このリカバリ作業を担当するのが Startup プロセスです。pg_control ファイル (起動制御情報を持つ重要なファイル) から「最後の Checkpoint LSN」を読み取り、そこから順に WAL レコードを再生 (Redo) して、最新のコミット状態までデータベースを巻き戻します。これが完了してConsistency Point に達すると、通常モードに移行して Postmaster がクライアント接続を受け付け始めます。

Standby サーバではこのプロセスが永続的に動き続けます。WAL Receiver が Primary から新しい WAL を受信するたびに、Startup プロセスがそれを順に再生して Standby の状態を Primary と同じに保ち続ける、というのが Streaming Replication の本質です。

PITR (Point-In-Time Recovery) でも、このプロセスが recovery_target_timerecovery_target_lsn で指定された地点まで WAL を再生する役目を担います。

クラッシュ復旧が遅い時に「Startup プロセスが動いているが redo done のログが出ない」という相談を受けたら、それは Redo に時間がかかっている合図です。max_wal_size を大きくしている本番だと、クラッシュ前に溜まっていた WAL の量に比例して復旧時間が伸びます。pg_stat_activitybackend_type = startup を確認すると進行中かどうかが分かります。
データフロー
pg_controlCheckpoint LSNWAL FilesRedo 対象Startup復旧 / 継続リプレイData Files復元先読取順次 ReadRedoPrimary では起動時のみ、Standby では永続的に動く
動作ステップ
1
Primary 起動時: ① postmaster が fork
2
Checkpoint レコードを発見
3
それ以降の WAL を順次リプレイ
4
Consistency Point に達したら通常モードへ
5
プロセスは終了。Standby: ⑤ ではなく永続的に WAL Receiver からの新着を待ってリプレイし続ける
注意点
archived WAL が壊れていると復旧で停止。recovery_target_action で挙動制御可。Standby で長すぎる遅延は Primary 側の更新負荷か Standby 側の I/O 不足を疑う。
関連パラメータ
recovery_target_time = ...recovery_target_lsn = ...restore_command = 'aws s3 cp ...'recovery_target_action = 'promote' / 'pause' / 'shutdown'
観察方法
pg_stat_activity (backend_type = startup) / ログの "redo done"

12. Logger プロセス

ROLE
PostgreSQL の標準エラー出力をログファイルに集約・ローテートする
PostgreSQL は通常運用中に大量のログを出力します。エラー、警告、スロークエリ、Checkpoint 完了、Autovacuum 実行、接続/切断、デッドロック発生、起動失敗など、運用に必要な情報が次から次に出てきます。これらは本番障害時の原因特定の最重要証拠で、適切に保存・管理しておく必要があります。

ところが、これらのログを各プロセスがそれぞれ標準エラー出力 (stderr) に吐くだけだと、systemd や journald 任せになりログローテーションや集中管理が面倒です。プロセスごとにバラバラなファイルに書かれてしまい、後で「あのエラーいつ起きた?」と調べる時に大変です。

そこで PostgreSQL は専用のログ集約プロセスを立ち上げる機能を持っています。それが Logger プロセスです。

仕組みは次の通りです。logging_collector = on にしておくと、Postmaster が起動時に Logger を fork します。Logger は全子プロセスの stderr を OS のパイプ経由で受け取り、それを 1 つのログファイルに時刻付きで書き込みます。ファイル名は log_filename (例: postgresql-%Y-%m-%d.log) のパターンで自動命名され、log_rotation_age (1 日) や log_rotation_size (10MB) に達すると自動で新しいファイルに切り替わります (ローテート)。

本番では logging_collector = on が定石で、これがないとログ管理がぐっと面倒になります。注意点として、ディスクが満杯になると Logger 自身が止まり、それに依存していたプロセスがフリーズする可能性があるので、ログディスク容量の監視も忘れずに。
データフロー
BackendstderrCheckpointerstderrAutovacuumstderr他全プロセスstderrLoggerパイプで集約log_directory自動ローテート書込全プロセスの stderr をパイプで集めてファイル化
動作ステップ
1
postmaster が fork
2
全ての子プロセスから stderr をパイプで受け取る
3
log_directory (pg_log/) にファイルを開く
4
log_filename パターンで自動命名 (例: postgresql-2026-06-10.log)
5
log_rotation_age (1d) や log_rotation_size でローテート
注意点
ディスクが満杯になると Logger 自体が止まり、依存していたプロセスがフリーズする可能性。log_truncate_on_rotation の設定で過去ログ自動削除も検討。
関連パラメータ
logging_collector = onlog_directory = 'pg_log'log_filename = 'postgresql-%Y-%m-%d.log'log_rotation_age = 1dlog_rotation_size = 10MB
観察方法
ファイル直接 (tail -f /var/log/postgresql/postgresql-*.log)

13. Stats Collector (PG 14 まで)

ROLE
pg_stat_* ビューに表示される統計情報を集めるプロセス
PostgreSQL の運用では pg_stat_user_tablespg_stat_databasepg_stat_replication といった pg_stat_* ビューを頼りにします。これらには「テーブルにアクセスされた回数」「インデックスが使われた回数」「I/O 量」「現在実行中のクエリ」など、本番運用に欠かせない情報がリアルタイムに格納されています。

このデータは、各プロセス (Backend やバックグラウンドプロセス) が自分の活動状況を統計値として記録し、それを集約することで作られます。PG 14 以前ではこの集約を専用プロセスが担当していました。それが Stats Collector です。

仕組みはこうです。Backend や各バックグラウンドプロセスが自分の活動 (例: テーブル X を 1 回 SELECT した) を UDP パケットで Stats Collector に送信し、Collector はそれをメモリ上で集計して 1 秒ごとに pg_stat_tmp/ に書き出します。pg_stat_* ビューを SELECT すると、Collector が pg_stat_tmp/ から値を読み出して返してくれていました。

ところが UDP は信頼性のない通信プロトコルなので、システム負荷が高いと送信パケットが落ちて統計値が抜けるという厄介な問題がありました。これを根本解決するため、PG 15 で「各プロセスが共有メモリに直接書き込む」方式に変更され、Stats Collector プロセスは廃止されました

PG 15 以降は ps コマンドで stats collector という名前のプロセスは見えなくなります。プロセスとしては存在しないが、pg_stat_* ビュー自体は引き続き使えるという形になりました。PG 14 以前から 15 への移行時に stats_temp_directory を tmpfs に置く設定を入れていた場合、設定削除が必要なので注意が必要です。
データフロー
Backend × NUDP 送信BG プロセス × NUDP 送信Stats Collectorメモリ集計pg_stat_tmp/1 秒毎に書出UDPUDP書込PG 15 で廃止 → 各プロセスが共有メモリに直接書込に変更
動作ステップ
1
PG 14 以前: ① 各 Backend / BG プロセスが統計を UDP で送信
2
Stats Collector がメモリ上で集計
3
1 秒ごとに pg_stat_tmp/ に書き出し
4
pg_stat_* クエリ時に Collector が読み出して返す。PG 15+: プロセスなし。各プロセスが共有メモリに直接書く
注意点
PG 15 移行時、stats_temp_directory を tmpfs に置いていた構成は不要に。監視スクリプトでパスを参照していたものは壊れる可能性あり。
関連パラメータ
stats_temp_directory = ... (PG 14 以前)track_counts / track_io_timing / track_functions (PG 15+ も同じ)
観察方法
pg_stat_* ビュー全般 / PG 15+ では pg_stat_kcache 等の拡張も追加可

14. Background Worker (汎用)

ROLE
拡張機能が独自に起動するバックグラウンドプロセスの枠
PostgreSQL には拡張機能 (extension) という仕組みがあり、本体に組み込まれていない機能を後から追加できます。たとえば pg_cron (DB 内 cron でジョブ実行)、TimescaleDB (時系列データの自動圧縮)、Citus (分散ノードの管理)、pg_partman (パーティション自動メンテ) などの拡張機能は、SQL クエリの裏で常時何かしらのバックグラウンド処理を動かす必要があります。

ところが、これらの拡張機能ごとに自前でプロセスを立ち上げてしまうと、PostgreSQL の管理外になり、異常終了時の再起動などができません。そこで PostgreSQL は「拡張機能用のバックグラウンドプロセス枠」を内蔵しています。これが Background Worker (BgWorker) の仕組みです。

拡張機能は「自分のコードを動かす Worker を、この枠で起動してください」と Postmaster に登録できます。Postmaster はそれを通常の子プロセスとして fork し、異常終了したら自動で再起動します (設定次第)。

仕組みは次のように動きます。① shared_preload_libraries に拡張機能名を指定して PostgreSQL を起動すると、② 拡張機能の _PG_init() 関数が呼ばれて BackgroundWorker を登録し、③ Postmaster が指定タイミング (起動時 or オンデマンド) で fork し、④ 拡張機能のコードが動き始めます。

同時起動できる枠の数は max_worker_processes (デフォルト 8) で決まります。Parallel Query や Logical Replication の Apply Worker もこの枠を共有して消費するので、複数拡張を使う本番環境では max_worker_processes = 16 などに増やしておくのが定石です。pg_stat_activitybackend_type = background worker として表示されます。
データフロー
preload_libraries拡張機能登録_PG_init()BgWorker 登録Postmasterfork タイミング判定Background Worker拡張のコード実行forkpg_cron / TimescaleDB / Citus などが使う汎用枠
動作ステップ
1
拡張機能が shared_preload_libraries で読み込まれる
2
_PG_init() で BackgroundWorker を登録
3
Postmaster が指定タイミング (起動時 / オンデマンド) で fork
4
拡張機能のコードが動く
5
死んだら自動再起動 (設定次第)
注意点
max_worker_processes が小さいと拡張機能の Worker が起動できずエラー。複数拡張を併用する場合は合算して 8〜16 に増やす。
関連パラメータ
max_worker_processes = 8 (拡張・Parallel・Logical Rep すべてで共有)shared_preload_libraries に拡張名を追加
観察方法
pg_stat_activity (backend_type = background worker / 拡張名)

15. Parallel Worker

ROLE
Parallel Query 実行時に Backend が一時的に起動するワーカー
PostgreSQL のクエリ実行は通常、1 つの Backend プロセスが 1 つの CPU コアで処理します。普段はこれで十分ですが、数千万行のフルテーブルスキャン (Seq Scan)、巨大な Hash Join、大量の集計などを 1 コアで処理するのは効率が悪く、複数の CPU コアを使って並列化したくなります。

そこで PostgreSQL は「クエリの一部を複数 CPU で並列処理する」仕組みを持っています。これが Parallel Query で、その実行を担うのが Parallel Worker です。

仕組みはこうです。Planner が「このクエリは並列化した方が速い」と判断すると、実行計画に Gather node を挿入します。Backend がクエリ実行中に Gather node に到達した瞬間、Postmaster に「Parallel Worker を N 個 fork してください」と要求し、Postmaster が短命な Worker プロセスを必要数 fork します。各 Worker は同じ実行計画の一部 (= 担当範囲) を並列にスキャン・処理し、結果を親の Backend (Gather node) に返します。Backend は受け取った結果を集約してクライアントへ返却し、クエリが終わると Worker は消滅します。

Parallel Worker はクエリ実行中のみ生きる短命プロセスです。同時に立ち上げられる総数は max_parallel_workers (デフォルト 8)、1 つのクエリで使える数は max_parallel_workers_per_gather (デフォルト 2) で決まります。

注意点は、OLTP 系の小さなクエリで Parallel が発動すると、フォーク自体のオーバーヘッドで逆に遅くなることがある点です。min_parallel_table_scan_size (テーブルサイズの下限) や parallel_setup_cost (フォーク開始コスト) で発動条件を調整できます。EXPLAIN ANALYZE の Workers Launched 表示で実際に何個 Worker が動いたかを確認できます。
データフロー
Backendクエリ実行Gather nodeプラン上の節点Postmasterfork 要求Worker 1Worker 2Worker N並列スキャンBackendGather で集約forkforkforkクエリ完了で Worker は消滅する短命プロセス
動作ステップ
1
Backend がクエリ実行中、Gather ノードに到達
2
Postmaster に Parallel Worker を要求
3
Postmaster が fork、Worker は親 Backend の Plan を受信
4
それぞれ自分の担当範囲をスキャン
5
親 Backend が Gather で結果を集約
6
クエリ完了で Worker は消滅
注意点
OLTP 向けの小さなクエリで Parallel が発動するとオーバーヘッドで逆に遅くなる。min_parallel_table_scan_sizeparallel_setup_cost で発動条件を調整。
関連パラメータ
max_parallel_workers = 8max_parallel_workers_per_gather = 2min_parallel_table_scan_size = 8MBparallel_setup_cost = 1000
観察方法
EXPLAIN ANALYZE の "Workers Launched" / pg_stat_activity (backend_type = parallel worker)

状況別バックグラウンドプロセス活動シミュレータ

ここまで各プロセスを個別に詳しく見てきました。最後に「同じ DB でも、どんな状況に置かれるかで各プロセスの忙しさが変わる」ことを観察します。下のタブで運用状況を切り替えると、各プロセスの「状態 (待機 / 通常 / 稼働中 / 高負荷 / 障害)」「活動量」「今やっていること」が連動して変化します。

通常運用 — 一般的なアプリ稼働
読み取り中心の Web アプリが普通にアクセスされている状態。書き込みも一定量発生し、各プロセスが標準的な頻度で動いています。
bgwriter
書出系
通常
200ms 毎に LRU 末尾の dirty page を少しずつディスクへ書出
checkpointer
書出系
待機
まだ checkpoint_timeout に達せず、待機
walwriter
書出系
通常
200ms 毎に WAL Buffer をディスクへ flush
archiver
WAL系
通常
たまに完成した WAL を archive_command で退避
autovac launcher
掃除系
通常
1 分毎に巡回、たまに Worker を起動
autovac worker
掃除系
通常
小さなテーブルの VACUUM / ANALYZE を時々実行
walsender
レプリ系
通常
WAL を逐次 Standby へ送信。レプリ遅延 < 1 秒
walreceiver
レプリ系
通常
WAL を受信して pg_wal/ に書き込み
startup
レプリ系
通常
Standby で受信 WAL を継続リプレイ
logger
監視系
通常
接続・スロークエリ・checkpoint 等のログを記録
stats
監視系
通常
クエリ実行 / I/O 統計を集計・更新
プロセス一覧の確認:SELECT pid, backend_type, state, query FROM pg_stat_activity ORDER BY backend_type で、 どの種類のプロセスが何個動いているかが一覧できます。本番監視ではこのクエリを定期実行して、想定外のプロセスがないか見ておくと安心です。
PG 15 の変更点:Stats Collector が廃止され、共有メモリ経由の直接書き込みに変更されました。これにより UDP パケットロスの心配がなくなり、統計の精度が向上。 移行時にカスタム監視スクリプトが影響を受ける可能性があるので確認してください。
SECTION 07

メモリ構造とファイルレイアウト

本章では、PostgreSQL が物理メモリと物理ディスクをどう使い分けているか、そのメモリ構造とファイルレイアウトについて学んでいきます。

PostgreSQL のメモリは大きく「共有メモリ」「プロセスローカルメモリ」の 2 系統に分かれています。共有メモリはすべてのプロセスから読み書きできる共通領域で、テーブルやインデックスのキャッシュ (Shared Buffers)、WAL の書き込みバッファ、進行中のトランザクション情報、ロック状態などを保持しています。プロセスローカルメモリは各 Backend プロセスが個別に持つ専用領域で、ソートやハッシュテーブルといったクエリごとの作業領域に使われます。

この 2 系統の使い分けが、PostgreSQL の性能と運用挙動を決めます。たとえば共有メモリ (shared_buffers) を大きくすればキャッシュヒット率は上がりますが、OS キャッシュとの二重化で逆効果になる範囲があります。プロセスローカル (work_mem) は接続数だけ掛け算で消費されるため、安易に増やすと OOM の原因になります。本章ではこの 2 系統の構造を図で俯瞰し、各領域の役割、メモリ使用量の見積もり方、そしてディスク上のデータディレクトリの構成までを一気に整理します。

メモリ構造の全体像

実 RAM 上での配置と、各プロセスがどこにアクセスするかを 1 枚にまとめた図です。 上部のプロセスローカル (各 Backend が独立) と、中央の共有メモリ (全プロセス共通) の 2 層がポイント。 下層のOS バッファキャッシュ + ディスクも含めて「3 段キャッシュ」として理解すると、I/O チューニング時の判断が早くなります。

PostgreSQL MEMORY LAYOUTRAM① プロセスローカル各 Backend / Worker が独立で確保Backend #1work_memtemp_buffersカタログキャッシュプランキャッシュBackend #2work_memtemp_buffersカタログキャッシュプランキャッシュ...(max_connections 個)掛け算で増える100 接続× 64MB× 3 sort= 19 GB② 共有メモリ全プロセスが同じ物理メモリを参照 (System V / POSIX shm)Shared Buffersshared_buffers (RAM × 25%)データページ (8KB) のキャッシュ。最重要。(テーブル本体・インデックス・ヒープページなど全部)WAL Bufferswal_buffers (16MB)WAL 書込み前バッファCLOG / pg_xact数 MBTx の commit 状態ProcArraymax_connections に比例全 XID / SnapshotLock Managerロック数に比例アクティブロック表その他: MultiXact / SubTrans / Predicate Lock /Replication Slots / 共有統計 (PG 15+) / BG Worker Slots③ OS バッファキャッシュ (Linux page cache)PG が直接管理しないが、ファイル読み出し時に OS が透過的にキャッシュ。effective_cache_size でプランナーに「これくらい使える」と伝える。④ ディスク (data_directory)base/ (heap, index) / pg_wal/ (WAL) / global/ (システム共有)pg_xact/ (CLOG 永続化) / pg_replslot/ などread/writeread/write (OS 経由)① プロセス独立 → ② 全プロセス共有 → ③ OS 透過キャッシュ → ④ 永続ディスク

共有メモリは PostgreSQL の心臓部。全プロセスが同じメモリ空間を参照することで、複数プロセスが協調してデータベースを動かせるようになっています。 ここでは 12 の主要領域それぞれについて「何のためにあるか」「サイズ感」「運用で気にすべきこと」を深掘りします。

1. Shared Buffers

データページ (テーブル・インデックス) のキャッシュshared_buffers (デフォルト 128MB → 本番は RAM の 25%)
なぜ必要か
PG はテーブルやインデックスを 8KB の「ページ」単位で扱います。ディスクから読み出したページをこのバッファに入れておけば、次回同じページを読む時はメモリだけで完結 → 桁違いに高速。ディスク I/O を最小化する最重要キャッシュです。
内部の詳細
本番では shared_buffers = RAM の 25% が目安。それ以上は OS のページキャッシュとの二重化で効率悪化。pg_buffercache 拡張でどのテーブルが何ページキャッシュされているか観察可。
チューニングの勘所
pg_stat_database の blks_hit / (blks_hit + blks_read) でキャッシュヒット率を確認。95% 以上が理想、90% を切るなら拡大検討。

2. WAL Buffers

WAL をディスク書き出し前に貯めるバッファwal_buffers (デフォルト 16MB、自動的に shared_buffers/32)
なぜ必要か
各 Backend がトランザクション変更を行うとき、まず WAL Buffer に書きます。これがディスク書き込みの「アラートエリア」になっていて、WAL Writer が定期的に書き出すまでメモリ上に保持されます。
内部の詳細
小さすぎるとコミット時の fsync 頻度が上がって遅くなる。大きすぎてもクラッシュ時のリスクが増えるだけで意味なし。デフォルトの自動計算 (shared_buffers/32) で大抵 OK。
チューニングの勘所
pg_stat_wal.wal_buffers_full が頻繁にカウントアップするなら手動で増やす (16MB → 32MB)。

3. CLOG (Commit Log)

各トランザクションが コミット済 / 中止 / 進行中 のどれかを記録数 MB 程度 (XID 数に比例、自動拡張)
なぜ必要か
MVCC で「あるタプルが見えるか」を判定する時、そのタプルを作った XID が CLOG で commit 済みか確認します。CLOG は 1 XID あたり 2 bit (4 状態) しか使わず、超高速参照できるよう設計されています。
内部の詳細
正式名は pg_xact (PG 10+)、それ以前は pg_clog。ディスク上に永続化されつつ、よく参照される最新部分は共有メモリのスロットでキャッシュ。
チューニングの勘所
通常は触らない。XID Wraparound 対策で 20 億 XID 経過前に FREEZE が必要 → autovacuum が自動対処。

4. MultiXact

複数トランザクションが同じ行に持つ共有ロック / FK ロック情報の管理数 MB (使用頻度に比例)
なぜ必要か
SELECT FOR SHARE や外部キー制約のチェックで、複数 Tx が同じ行に「読んでます」マークをつける必要があります。1 タプルに複数の Tx IDを記録できないので、代わりに「MultiXact ID」という間接参照を使います。
内部の詳細
pg_multixact 配下のメンバーリストにマッピング。長期トランザクション + 大量 FK チェックで肥大化することがあり、autovacuum_multixact_freeze_max_age で凍結タイミングを制御。
チューニングの勘所
pg_stat_database.mxid_age が老化していたら要 VACUUM。MultiXact wraparound も Wraparound 対象。

5. SubTrans

サブトランザクション (SAVEPOINT) の親子関係を記録小さい (SAVEPOINT 数に比例)
なぜ必要か
SAVEPOINT を打つと内部的にサブトランザクションが作られます。各サブ Tx に独自の XID が割り当てられるので、「このサブ Tx の親は誰か」を引けるようにする必要があり、それを担うのが SubTrans です。
内部の詳細
pg_subtrans 配下にディスク永続化。ORM が EXCEPTION ハンドリングで SAVEPOINT を多用すると参照頻度が上がる。
チューニングの勘所
通常は触らない。SAVEPOINT を毎クエリ打つアンチパターン (一部 ORM のデフォルト) を見たら止める。

6. ProcArray

現在アクティブな全プロセスの XID とスナップショット情報max_connections × 数百 byte
なぜ必要か
トランザクション開始時にスナップショットを作る = 「いま実行中の他の XID 一覧を取る」操作が頻繁に発生します。これは ProcArray を全スキャンして得るため、max_connections が大きいほど 1 つのスナップショット作成が遅くなります。これが「接続数を増やすと一律遅くなる」根本原因。
内部の詳細
PG 14 以前は線形スキャン、PG 14+ ではある程度最適化されたものの依然として接続数の影響大。
チューニングの勘所
max_connections を 200 を超える場合は PgBouncer で接続数を減らすのが定石。本番で max_connections = 1000 など見たら見直しを。

7. Lock Manager (LockTable)

全アクティブロックを管理する共有ハッシュテーブルmax_locks_per_transaction × max_connections × 約 270 byte
なぜ必要か
PG のロックは「テーブル」「行」「Advisory」など何でもこのテーブルで一元管理。各ロック取得は LockTable に行を追加 → 解放時に削除、という操作になります。pg_locks ビューはこれを覗いているだけ。
内部の詳細
上限を超えると out of shared memory エラー。大量パーティション (1000+) を 1 トランザクションで触ると、max_locks_per_transaction (デフォルト 64) を超えやすい。
チューニングの勘所
巨大パーティション環境では max_locks_per_transaction を 128〜256 に増やす。pg_locks の行数を監視すると傾向が見える。

8. Predicate Lock Manager

Serializable 分離レベルの述語ロック (predicate lock) の管理max_pred_locks_per_transaction に比例
なぜ必要か
Serializable では「読んだ範囲」も記録して、後続の更新と矛盾がないか検出します。これに使う特殊なロックが predicate lock。通常のロックとは別管理になっており、SSI (Serializable Snapshot Isolation) の心臓部です。
内部の詳細
上限超えると Serialization Failure が増える。Serializable 分離を使わなければ実質ゼロのオーバーヘッド。
チューニングの勘所
Serializable を本格利用する場合のみ調整。max_pred_locks_per_transaction = 128 以上推奨。

9. 共有統計領域 (PG 15+)

pg_stat_* ビューに出る統計データ小さい (テーブル数に比例)
なぜ必要か
PG 14 までは Stats Collector プロセスが UDP で集めて pg_stat_tmp/ に保存していました。PG 15 でこれを廃止し、各プロセスが共有メモリに直接書き込むモデルに変更。UDP パケットロスの問題が解消され、統計の信頼性が向上しました。
内部の詳細
プロセス側からは pgstat_* 関数で更新、参照側は pg_stat_* ビュー経由でアクセス。
チューニングの勘所
通常は意識しない。PG 15 移行時に stats_temp_directory の設定を削除する必要あり。

10. Replication Slots

WAL Sender / 論理レプリ の進捗管理max_replication_slots × 約 1KB
なぜ必要か
Subscriber 側がどの LSN まで受信完了したかを Primary 側で記憶し、まだ未受信の WAL を削除しないようにする仕組み。物理スロットと論理スロットの 2 種類があり、論理レプリではほぼ必須。
内部の詳細
スロットを残したまま Subscriber を停止すると WAL が無限蓄積 → ディスク満杯リスク。PG 13+ の max_slot_wal_keep_size で上限保護必須。
チューニングの勘所
pg_replication_slots.confirmed_flush_lsn の進捗が止まっていないか監視。不要なスロットは速やかに DROP。

11. BGWriter / WAL Writer 統計

バックグラウンドプロセスの動作カウンタ統計用 (小)
なぜ必要か
bgwriter / WAL Writer / Checkpointer の動作状況 (書込ページ数・実行回数) を集めて pg_stat_bgwriter / pg_stat_wal で見えるようにするための共有領域。
内部の詳細
PG 17 で pg_stat_bgwriter が pg_stat_checkpointer と分離された (Checkpointer の統計が独立)。
チューニングの勘所
本番チューニングでは pg_stat_bgwriter.buffers_backend の増加トレンドを必ず追う。

12. Background Worker Slots

カスタム BG ワーカー (拡張機能 / Parallel / Logical Rep) の管理max_worker_processes × 数百 byte
なぜ必要か
pg_cron・TimescaleDB・Citus などの拡張機能、Parallel Worker、論理レプリ Apply Worker など、Postmaster が管理する全 BG ワーカーがこのスロットを使います。スロット数が上限。
内部の詳細
max_worker_processes (デフォルト 8) は全用途で共有。Parallel と論理レプリと拡張すべて合算する必要あり。
チューニングの勘所
拡張機能を複数併用するなら 16〜32 へ拡大。max_parallel_workers と max_logical_replication_workers の合計が max_worker_processes を超えないように。

プロセスローカルメモリ

各 Backend プロセスが独立で確保する領域。「同時 100 接続 × work_mem 4MB = 400MB」のように掛け算で増えるのがポイントです。

work_memSort・Hash・Materialize 用。1 クエリ内の操作毎・並列ワーカー毎に確保
maintenance_work_memVACUUM・CREATE INDEX 用。同時実行が少ないので大きく設定可
temp_buffers一時テーブル用ローカルバッファ。セッション単位で独立
カタログキャッシュpg_class・pg_attribute 等。テーブル/カラム数で増大
プラン/クエリキャッシュPrepared Statement のプランを保持
CurrentMemoryContextクエリ内で動的確保される作業領域。Executor が頻繁に使う
クライアントとのソケットバッファTCP の送受信用。通常は OS 管理

メモリ使用量の計算式

# 共有メモリの最低必要量
共有メモリ = shared_buffers
          + wal_buffers
          + max_connections × (proc 管理領域 ~10KB)
          + max_locks_per_transaction × max_connections × (ロック領域 ~270 byte)
          + max_replication_slots × (~数 KB)
          + その他 (CLOG, MultiXact 等)

# プロセスローカルメモリの最大量
ローカル = max_connections
        × work_mem
        × 想定同時 sort/hash 操作数
        + max_connections × (バックエンド基本 ~10MB)
        + autovacuum_max_workers × maintenance_work_mem

# 全体
合計 = 共有メモリ + ローカル合計 + OS バッファキャッシュ + その他オーバーヘッド

データディレクトリの中身

PG の物理ファイルは data_directory (通常 /var/lib/postgresql/16/main) に集約されています。ここの構造を理解すると、トラブル時の調査が早くなります。

base/DB 毎のサブディレクトリ。実テーブル・インデックスのデータファイル
base/<oid>/<relfilenode>実際のデータファイル。1 ファイル 1GB 制限、超えると .1, .2 と分割
global/クラスタ全体で共有するシステムテーブル (pg_database 等)
pg_wal/WAL ファイル群 (16MB 固定)。アーカイブされたら削除される
pg_xact/CLOG (Commit Log) の永続化先
pg_multixact/MultiXact 情報
pg_subtrans/サブトランザクション情報
pg_tblspc/テーブルスペースへのシンボリックリンク
pg_replslot/レプリケーションスロットの状態
pg_logical/論理レプリの状態管理
pg_stat_tmp/統計の一時ファイル (PG 14 以前)
pg_log/ または log/PG ログファイル (logging_collector が ON の場合)
postgresql.conf主要設定ファイル
pg_hba.conf認証設定
pg_ident.confユーザー名マッピング
postmaster.pid稼働中の Postmaster の PID とソケット情報
PG_VERSIONクラスタのバージョン番号 (1 行)

relfilenode と OID

-- テーブル名 → 物理ファイルパスを引く
SELECT pg_relation_filepath('orders');
-- → base/16384/16720

-- relfilenode 取得
SELECT oid, relname, relfilenode, pg_relation_size(oid) AS size
FROM pg_class
WHERE relname = 'orders';

-- 注意:
-- ・relfilenode は VACUUM FULL や TRUNCATE で変わる
-- ・oid は変わらない (PG 内部の識別子)
-- ・1GB を超えると .1, .2 ... と分割される

-- ファイルサイズ確認
ls -lh /var/lib/postgresql/16/main/base/16384/16720*
ファイル直接編集は厳禁:データディレクトリ内のファイルを直接 vi で編集したり、稼働中に rm したりすると即破損します。 postgresql.conf 以外はすべて「PG が自分で管理するもの」と覚えてください。
ディスク使用量の調査:SELECT pg_size_pretty(pg_database_size(current_database())) で DB 全体、pg_table_size('orders') でテーブル単独、pg_indexes_size('orders') でインデックス合計サイズが取れます。
SECTION 08

設定ファイル

本章では、PostgreSQL の挙動を制御する設定ファイル群と、その反映の仕組みについて学んでいきます。

PostgreSQL の動作は 4 つの設定ファイルと、それらを補うパラメータ階層によってコントロールされます。postgresql.conf がメイン設定、pg_hba.conf が接続認証ルール、pg_ident.conf が OS ユーザー名と DB ロール名のマッピング、postgresql.auto.confALTER SYSTEM による動的書き換え用 — それぞれが役割を分担し、組み合わさって 1 つの挙動を決めます。

どのファイルに何を書くべきか」「どうやって反映させるか」「どこから上書きされる可能性があるか」を把握していないと、本番で「設定したはずなのに効かない」「再起動を忘れていて反映されない」「auto.conf が勝手に上書きしている」といったトラブルに直面します。本章では、4 つのファイルそれぞれの役割と書き方、パラメータが反映されるタイミング (context)、reload と restart の使い分け、そして設定のベストプラクティスまでを順に整理します。

4 つの主要設定ファイル

postgresql.conf
役割: 主設定。メモリ・接続数・ログ・WAL・レプリ等すべての挙動パラメータ
編集方法: 管理者が手動編集 (テキストエディタ)
使う場面: 最も触る機会が多い
pg_hba.conf
役割: ホストベース認証 (Host-Based Authentication)。誰がどこから何の方式でログインできるか
編集方法: 管理者が手動編集
使う場面: セキュリティ設定の中心
pg_ident.conf
役割: OS ユーザー名と PG ロール名のマッピング (peer / cert / gss 認証で使う)
編集方法: 管理者が手動編集
使う場面: OS 統合認証を使う時のみ
postgresql.auto.conf
役割: ALTER SYSTEM コマンドが自動書き込むファイル。postgresql.conf より優先される
編集方法: 手で編集しない (ALTER SYSTEM 経由のみ)
使う場面: 本番で動的に設定を変えたい時

設定の優先順位 (上が強い)

① SET LOCAL (トランザクション内)COMMIT/ROLLBACK で消える、最も強い② SET (セッション内)接続切断で消える③ ALTER ROLE / ALTER DATABASE特定ロール・特定 DB で適用④ ALTER SYSTEM (postgresql.auto.conf)クラスタ全体・永続化⑤ postgresql.conf (手動編集)クラスタ全体・永続化、auto.conf に上書きされる⑥ コマンドライン引数 (postgres -c ...)起動時のみ⑦ コンパイル時のデフォルト最弱

パラメータの context — いつ反映されるか

context反映タイミング
internal変更不可 (コンパイル時)block_size, wal_block_size
postmaster完全再起動が必要shared_buffers, max_connections, port
sighuppg_ctl reload (再起動なし)work_mem, log_*, autovacuum, archive_*
superuser-backend次の接続から (スーパーユーザーのみ)log_connections
backend次の接続からclient_encoding
superuser即時 (スーパーユーザーのみ)log_min_messages
user即時 (誰でも SET 可)search_path, work_mem (上書き)
「設定したのに効かない」の原因 No.1:変更したパラメータの context が postmaster なのに reload しかしていない、あるいはauto.confで上書きされていてファイルだけ書き換えても効かない。 必ず SHOW パラメータ名 で実値を確認しましょう。

postgresql.conf

メイン設定ファイル。1,000 以上のパラメータがあり、13 のカテゴリに分かれています。 ファイルの場所は SHOW config_file; で確認できます (典型的には /etc/postgresql/16/main/postgresql.conf)。

全体は # から始まるコメント + key = value 形式。 値の単位は MB / GB (メモリ)、ms / s / min / h (時間)、on / off (真偽値) など型に応じて。 引用符が必要なのは文字列 (listen_addresses = '*') のみで、数値・enum は不要。

主要 13 カテゴリ
File Locations
data_directory / config_file / hba_file
PG が使う各種ファイルの場所。通常 OS パッケージが設定済
Connections and Authentication
listen_addresses / port / max_connections / ssl
クライアント接続の受付・認証設定
Resource Usage (Memory)
shared_buffers / work_mem / maintenance_work_mem / effective_cache_size
メモリ割当。最重要のチューニング対象
WAL
wal_level / max_wal_size / checkpoint_timeout / archive_*
WAL 動作・チェックポイント・アーカイブ
Replication
max_wal_senders / max_replication_slots / hot_standby / synchronous_standby_names
Streaming/Logical Replication 関連
Query Tuning
random_page_cost / effective_io_concurrency / default_statistics_target
プランナーへのヒント。SSD なら random_page_cost = 1.1
Reporting and Logging
logging_collector / log_directory / log_min_duration_statement / log_line_prefix
ログの取り方・スロークエリ記録
Autovacuum
autovacuum / autovacuum_max_workers / autovacuum_*_scale_factor
VACUUM/ANALYZE の自動実行設定
Client Connection Defaults
search_path / timezone / statement_timeout / idle_in_transaction_session_timeout
クライアント接続時のデフォルト値・タイムアウト
Lock Management
deadlock_timeout / max_locks_per_transaction
ロック関連の制限
Version and Platform Compatibility
standard_conforming_strings / backslash_quote
古い PG / 他 RDBMS との互換性
Error Handling
restart_after_crash
クラッシュ時の挙動
Customized Options (拡張機能)
shared_preload_libraries / pg_stat_statements.* / auto_explain.*
拡張機能の事前ロード・拡張固有設定
主要パラメータを 1 つずつ詳しく解説

以下、本番でよく触る 34 個のパラメータについて、 「何をする値か」「デフォルト」「推奨値とその理由」「よくあるミス」を 1 つずつ解説します。

接続関連
listen_addressesdefault: 'localhost'
役割: クライアント接続を受け付ける IP アドレス。
推奨: 本番は '*' (全 IF) か、特定 IP のみを列挙。クラウドではプライベート IP のみが安全
注意: 反映には再起動が必要 (postmaster context)。Security Group / pg_hba.conf でも別途制限を
portdefault: 5432
役割: 受付ポート番号。
推奨: デフォルト 5432 のままで OK。マルチインスタンスの時のみ変更
注意: 変更したらクライアント側の接続文字列も全部書き換える必要あり
max_connectionsdefault: 100
役割: PG が同時に受け付ける最大接続数。
推奨: PgBouncer 併用なら 100〜200 で OK。直接接続なら 200〜500。これ以上は ProcArray スキャンが遅くなる
注意: 値を上げると共有メモリ消費も増加 (1 接続 ~10KB の管理領域)。reload 不可・再起動必須
superuser_reserved_connectionsdefault: 3
役割: スーパーユーザー専用に予約する接続枠。
推奨: 本番では 5 程度に。max_connections 満杯時も管理者が入れるように
注意: これがないと「全接続埋まって管理者すら入れない」事態に
メモリ関連
shared_buffersdefault: 128MB
役割: データページ (テーブル・インデックス) のキャッシュサイズ。最重要のメモリパラメータ。
推奨: 本番は RAM の 25% (例: 16GB マシンなら 4GB)。それ以上は OS キャッシュとの二重化で逆効果
注意: デフォルト 128MB は本番では絶対に小さすぎる。再起動必須
effective_cache_sizedefault: 4GB
役割: 「OS バッファキャッシュ含めて利用可能なメモリ量」のプランナーへのヒント。実メモリ確保ではない。
推奨: RAM × 50〜75% (例: 16GB なら 8〜12GB)。大きいほど Planner が Index Scan を選びやすくなる
注意: 実メモリは食わないので慎重になりすぎなくて OK。reload で反映
work_memdefault: 4MB
役割: 1 つのソート・ハッシュ・Materialize 操作が使える最大メモリ。これを超えるとディスクスピル (一時ファイル) でクエリが遅くなる。
推奨: 64MB〜256MB が一般的。ただし接続数 × クエリ内操作数で掛け算される
注意: 小さすぎ → クエリが遅い、大きすぎ → 同時実行で OOM。SET LOCAL でクエリ単位の調整も可
maintenance_work_memdefault: 64MB
役割: VACUUM・CREATE INDEX・ALTER TABLE 等の保守作業が使えるメモリ。
推奨: 1〜2GB。同時実行が少ないので大胆に設定可。VACUUM / CREATE INDEX が劇的に速くなる
注意: autovacuum_work_mem を別に設定すれば autovacuum 専用にできる
wal_buffersdefault: -1 (自動)
役割: WAL をディスク書き出し前に貯めるバッファ。
推奨: デフォルトの -1 (shared_buffers の 1/32、最大 16MB) で OK。書込み多い系で 32MB に上げることも
注意: 小さすぎると wal_buffers_full が頻発してコミット時の同期コスト増
temp_buffersdefault: 8MB
役割: 一時テーブル用のローカルバッファ。セッション単位で独立。
推奨: 一時テーブルを多用するバッチでは 64MB〜256MB に
注意: デフォルトでも OK。最初に一時テーブルを触った時に確保される
WAL / Checkpoint
wal_leveldefault: replica
役割: WAL に記録する情報の詳細度。minimal (クラッシュ復旧のみ) / replica (Streaming Rep 可) / logical (論理レプリ可)。
推奨: 本番は最低 replica。論理レプリ使うなら logical
注意: 変更には再起動必要。logical にしても性能ペナルティは数 % で実用範囲
max_wal_sizedefault: 1GB
役割: 次の Checkpoint までに溜まる WAL の上限目安。これを超えると強制 Checkpoint 発動。
推奨: 本番は 4〜16GB に。小さいと Checkpoint 頻発で I/O 波が立つ
注意: 大きすぎるとクラッシュ復旧時間が長くなる。バランスが重要
min_wal_sizedefault: 80MB
役割: WAL ファイルを最小限保持するサイズ。これより少なくならない。
推奨: 本番は 1〜2GB。WAL リサイクルで I/O が減る
注意: ディスクに余裕があれば大きめでも害なし
checkpoint_timeoutdefault: 5min
役割: 時間経過による Checkpoint の発動間隔。
推奨: 5〜30 分。長くするとクラッシュ復旧が遅くなるが、I/O 負荷は下がる
注意: max_wal_size と組み合わせて I/O 分散とクラッシュ復旧時間のバランスを取る
checkpoint_completion_targetdefault: 0.9
役割: Checkpoint の書き込みを何割の時間で完了するか。0.9 なら 5min × 0.9 = 4min 30sec で完了。
推奨: 0.9 のまま。I/O スパイクを平準化する効果あり
注意: これがないと Checkpoint 発動瞬間に I/O 急増
archive_modedefault: off
役割: WAL アーカイブ機能を有効化するか。PITR / Streaming Replication の基盤。
推奨: 本番は on (絶対)。バックアップとレプリ両方で必要
注意: 変更には再起動必要。off のままだと PITR できない
archive_commanddefault: ''
役割: 満杯になった WAL ファイルを退避するシェルコマンド。%p (元パス) / %f (ファイル名) を置換。
推奨: 'aws s3 cp %p s3://bucket/wal/%f' 等。終了コード 0 で成功とみなされ次へ
注意: 失敗が続くと pg_wal/ に WAL が溜まり続けディスク満杯リスク。pg_stat_archiver を必ず監視
wal_compressiondefault: off (PG 15+ は on)
役割: WAL の圧縮を有効化。圧縮アルゴリズムは pglz / lz4 / zstd (PG 15+) から選択。
推奨: PG 15+ は on (zstd) 推奨。ディスク・ネットワーク帯域が大幅節約
注意: CPU を少し使うが、Streaming Replication 環境では明確に有利
Replication
max_wal_sendersdefault: 10
役割: Streaming Replication で同時に WAL を送信できる最大プロセス数。Standby 1 台 + Subscriber 数 + pg_basebackup 同時実行数の合計を確保。
推奨: 本番では 10〜30 程度。Standby 2 台 + Subscriber 2 + pg_basebackup 用に余裕を持つ
注意: 再起動必要。論理レプリも 1 Subscription につき 1 walsender を消費
max_replication_slotsdefault: 10
役割: レプリケーションスロットの最大数。物理スロット + 論理スロット合算。
推奨: 本番は 10〜20。論理レプリ多用時はもっと
注意: スロットを残したまま Subscriber 停止すると WAL 蓄積 → ディスク満杯リスク
max_slot_wal_keep_sizedefault: -1 (無制限)
役割: PG 13+: 1 スロットが保持できる WAL の上限。これを超えるとスロットが無効化される。
推奨: 本番は 50GB 程度。スロット起因のディスク満杯事故を防げる
注意: 無効化されたスロットを使う Subscriber は完全 resync が必要に
hot_standbydefault: on
役割: Standby が読み取りクエリを受け付けるか。
推奨: on のまま。読み取り分散の前提
注意: off にする理由は通常ない
synchronous_standby_namesdefault: ''
役割: 同期コミット対象の Standby を列挙。空なら全て非同期。
推奨: クリティカル系のみ 'standby1' 等で同期化。レイテンシが上がる代わりにデータロスゼロ
注意: 同期 Standby が停止すると Primary のコミットも止まる。複数指定が安全
synchronous_commitdefault: on
役割: コミット時の同期レベル。on / local / remote_write / remote_apply / off。
推奨: 本番は on (デフォルト)。データロス許容できる解析系のみ off で 2 倍以上のスループット
注意: off にするとクラッシュ時に直前数百 ms のコミットが消える
Autovacuum
autovacuumdefault: on
役割: Autovacuum 機能を有効化。
推奨: 絶対 on。off にしてはいけない。デッドタプル蓄積で数日で性能崩壊
注意: 個別テーブルで止めたい場合は ALTER TABLE ... SET (autovacuum_enabled = false) で限定的に
autovacuum_max_workersdefault: 3
役割: 同時に動ける Autovacuum Worker の数。
推奨: 本番は 4〜8。テーブル数が多い環境では増やすと並列度上がる
注意: max_worker_processes も合わせて増やす必要あり
autovacuum_naptimedefault: 1min
役割: Autovacuum Launcher が各 DB を巡回する間隔。
推奨: 1min のまま。短くしても効果薄い、長くすると対応遅れる
注意: DB が多い (>50) なら 30s に短縮も検討
autovacuum_vacuum_scale_factordefault: 0.2
役割: テーブルサイズの何割のデッドタプルが溜まったら VACUUM 発動するか。0.2 = 20%。
推奨: 0.1 (10%) に下げると VACUUM 頻度上昇 → デッドタプル少なく保てる
注意: 大きいテーブルでは絶対値 (autovacuum_vacuum_threshold) と組み合わせる
autovacuum_vacuum_thresholddefault: 50
役割: VACUUM 発動の絶対値しきい値。scale_factor × n_live_tup + threshold で総閾値が決まる。
推奨: 通常 50 のまま。小さいテーブルが頻繁 VACUUM されるのを避けるため
autovacuum_vacuum_cost_limitdefault: 200
役割: Autovacuum 1 回の I/O コスト上限。これを超えると一時停止し autovacuum_vacuum_cost_delay 待つ。
推奨: 本番は 2000〜10000 に上げて積極実行。デフォルトは保守的すぎる
注意: I/O が遅い環境ではデフォルト維持が安全
autovacuum_freeze_max_agedefault: 200000000 (2 億)
役割: XID Wraparound 防止のため強制 VACUUM FREEZE が走るしきい値。
推奨: デフォルト 2 億のまま。これを大きくすると wraparound 時の VACUUM が重くなる
Logging
logging_collectordefault: off
役割: PG ログを内蔵 Logger プロセス経由でファイル保存するか。
推奨: 本番は on。off だと syslog 任せになりログローテーション等が面倒
注意: 再起動必要。systemd 環境では journald との二重化に注意
log_directorydefault: 'log'
役割: ログファイル出力ディレクトリ。
推奨: デフォルトの 'log' (data_directory 内) または '/var/log/postgresql'
注意: 別ボリュームに分けるとログ書込みで DB I/O を圧迫しない
log_filenamedefault: 'postgresql-%Y-%m-%d_%H%M%S.log'
役割: ログファイル名のパターン (strftime 形式)。
推奨: 'postgresql-%Y-%m-%d.log' で日次。月次は %m まで含める
注意: %H%M%S を含めると再起動毎に新ファイルになるので注意
log_min_duration_statementdefault: -1 (無効)
役割: 指定 ms 以上のクエリを「スロークエリ」としてログ記録。
推奨: 本番は 1000 (1 秒) 程度。重要 OLTP では 100 ms にすることも
注意: 0 にすると全クエリ記録 (デバッグ時のみ)
log_line_prefixdefault: '%m [%p] '
役割: 各ログ行の先頭に付ける情報。%t / %p / %u / %d / %a / %h など。
推奨: '%t [%p]: db=%d,user=%u,app=%a,client=%h ' で情報リッチ
注意: pgbadger 等で解析する場合は pgbadger 推奨フォーマットに合わせる
log_lock_waitsdefault: off
役割: deadlock_timeout を超えるロック待ちをログ記録。
推奨: 本番は on (必須)。デッドロック予兆や長時間ロックを発見できる
注意: ログ量が増えるが、本番運用では絶対必要
log_checkpointsdefault: off (PG 15+ は on)
役割: Checkpoint 実行情報をログ記録。
推奨: 本番は on。Checkpoint 頻度・所要時間が見える
log_connections / log_disconnectionsdefault: off
役割: 接続・切断をログ記録。
推奨: on を推奨。誰がいつ繋いだかが追える
注意: PgBouncer 経由の大量接続でログが膨張するなら disconnection だけ on
log_temp_filesdefault: -1
役割: 指定サイズ以上の一時ファイル (work_mem 不足によるソートスピル等) をログ記録。
推奨: 本番は 0 (全記録)。work_mem 不足の検出に必須
プランナー / Query Tuning
random_page_costdefault: 4.0
役割: ランダムアクセス (Index Scan) の相対コスト。seq_page_cost = 1.0 に対する比率。
推奨: SSD なら 1.1、HDD なら 4.0 のまま。NVMe なら 1.0 でも
注意: これを下げると Index Scan が選ばれやすくなる
seq_page_costdefault: 1.0
役割: シーケンシャルアクセスの基準コスト。
推奨: 1.0 のまま (基準値)
effective_io_concurrencydefault: 1
役割: Bitmap Heap Scan などで同時発行する I/O 数のヒント。
推奨: SSD は 200、NVMe は 256、HDD は 1〜2
注意: OLTP では大差ないが分析クエリで効く
default_statistics_targetdefault: 100
役割: ANALYZE が集める統計のヒストグラム解像度。
推奨: 通常 100。重要カラムだけ ALTER TABLE で 1000 に上げる
注意: グローバルに上げると ANALYZE が遅くなる
jitdefault: on
役割: JIT コンパイル (PG 11+)。重い分析クエリを高速化。
推奨: OLTP では off にしてもよい (短いクエリで JIT コスト > 効果)
注意: jit_above_cost = 100000 で発動コストを調整可
タイムアウト (本番で必須)
statement_timeoutdefault: 0 (無制限)
役割: 1 つの SQL 文の最大実行時間。これを超えるとキャンセル。
推奨: 本番では絶対設定。Web 系は 30s、バッチは 30min など用途別に
注意: 長時間クエリの暴走で全体が止まる事故を防ぐ最重要パラメータ
idle_in_transaction_session_timeoutdefault: 0 (無制限)
役割: BEGIN したまま放置されたトランザクションをタイムアウト切断。
推奨: 本番では 5min 必須。VACUUM 阻害・ロック保持の主要原因を断つ
注意: これがないと長時間 Tx で本番障害になる典型パターン
lock_timeoutdefault: 0 (無制限)
役割: ロック取得の最大待ち時間。
推奨: 本番は 1〜5s。マイグレーションでは慎重に SET LOCAL で短く
注意: ALTER TABLE が長時間ブロックする事故を防げる
idle_session_timeoutdefault: 0 (無制限、PG 14+)
役割: idle (トランザクション外) 接続のタイムアウト。
推奨: 本番は 30min 程度。接続リーク対策
注意: アプリの connection pool 設定と組み合わせる
deadlock_timeoutdefault: 1s
役割: デッドロック検出までの待ち時間。
推奨: 1s のまま。短くすると false detection、長くするとデッドロック解消遅延
拡張機能
shared_preload_librariesdefault: ''
役割: 起動時に事前ロードする拡張機能のリスト。pg_stat_statements 等は必須。
推奨: 本番は 'pg_stat_statements,auto_explain' は最低限。pg_cron / pg_buffercache 等も用途次第
注意: 変更には再起動必要。ロード順序が依存関係を満たす必要あり
pg_stat_statements.maxdefault: 5000
役割: 統計を保持するクエリ数の上限。
推奨: 本番は 10000。動的 SQL が多いと埋まりやすい
pg_stat_statements.trackdefault: top
役割: 記録するクエリの粒度。top (トップレベルのみ) / all (関数内も) / none。
推奨: all にすると関数内 SQL も記録され調査しやすい
本番テンプレ — まとめてコピペ用
# ─── 接続 ───
listen_addresses = '*'
port = 5432
max_connections = 200            # PgBouncer 併用前提
superuser_reserved_connections = 5

# ─── メモリ (RAM 16GB を想定) ───
shared_buffers = 4GB
effective_cache_size = 12GB
work_mem = 64MB
maintenance_work_mem = 1GB
wal_buffers = -1                 # 自動 (16MB)

# ─── WAL / Checkpoint ───
wal_level = replica
max_wal_size = 4GB
min_wal_size = 1GB
checkpoint_timeout = 5min
checkpoint_completion_target = 0.9
archive_mode = on
archive_command = 'aws s3 cp %p s3://bucket/wal/%f'
wal_compression = zstd           # PG 15+

# ─── Replication ───
max_wal_senders = 10
max_replication_slots = 10
max_slot_wal_keep_size = 50GB
hot_standby = on
synchronous_commit = on

# ─── Autovacuum ───
autovacuum = on
autovacuum_max_workers = 4
autovacuum_naptime = 1min
autovacuum_vacuum_scale_factor = 0.1
autovacuum_vacuum_cost_limit = 2000

# ─── Logging ───
logging_collector = on
log_directory = 'pg_log'
log_filename = 'postgresql-%Y-%m-%d.log'
log_min_duration_statement = 1000
log_line_prefix = '%t [%p]: db=%d,user=%u,app=%a,client=%h '
log_lock_waits = on
log_checkpoints = on
log_connections = on
log_disconnections = on
log_temp_files = 0

# ─── プランナー (SSD 想定) ───
random_page_cost = 1.1
effective_io_concurrency = 200
default_statistics_target = 100

# ─── タイムアウト (絶対設定) ───
statement_timeout = 30s
idle_in_transaction_session_timeout = 5min
lock_timeout = 1s
idle_session_timeout = 30min     # PG 14+

# ─── 拡張機能 ───
shared_preload_libraries = 'pg_stat_statements,auto_explain'
pg_stat_statements.max = 10000
pg_stat_statements.track = all

pg_hba.conf

ホストベース認証 (Host-Based Authentication) の設定ファイル。 「誰がどこから何の方式でログインできるか」を 5 列 (+ 1 オプション列) で上から順に評価し、最初にマッチしたルールで認証します。 順序を間違えると、強い認証ルールが弱いルールに上書きされる事故が起きるので並び順が極めて重要です。

ファイル場所は SHOW hba_file; で確認可能。編集後は SELECT pg_reload_conf(); または pg_ctl reload で反映 (再起動不要)。

ファイル構造
# TYPE    DATABASE       USER          ADDRESS              METHOD            [OPTIONS]
local     all            all                                 peer
hostssl   mydb           app_user      10.0.0.0/8           scram-sha-256
hostssl   replication    replicator    10.0.1.0/24          scram-sha-256
hostssl   all            +readonly     10.0.0.0/8           scram-sha-256
hostnossl all            all           0.0.0.0/0            reject
列① TYPE — 接続経路
localUnix domain socket 経由 (同一ホスト)
hostTCP/IP 経由 (SSL あり/なし両方)
hostsslTCP/IP かつ SSL/TLS 必須
hostnosslTCP/IP かつ SSL/TLS 不可 (通常は reject に使う)
hostgssencTCP/IP かつ GSSAPI 暗号化必須
hostnogssencTCP/IP かつ GSSAPI 暗号化なし
列② DATABASE — 対象 DB
all全 DB
replicationStreaming Replication 用 (特別、通常 DB 接続には適用されない)
sameuserユーザー名と同名の DB のみ
samerole / +groupメンバーであるロール名と同名の DB
mydb,otherdbカンマ区切りで複数指定可
@filename外部ファイルからロード
列③ USER — 対象ロール
all全ユーザー
+groupnameロール (グループ) のメンバー全員
user1,user2カンマ区切り複数
@filenameファイルからロード
列④ ADDRESS — 接続元 IP
10.0.0.0/8CIDR 表記。サブネット指定
192.168.1.5/32単一 IP
samehost / samenetサーバと同一ホスト / 同一サブネット
.example.comドメイン (DNS 逆引き必須、推奨しない)
(空欄)local 行では指定不要
列⑤ METHOD — 認証方式
trustパスワード不要。本番では絶対禁止 ❌
reject即拒否。明示的なブラックリスト用
scram-sha-256パスワード認証 (推奨 ✓)
md5旧パスワード認証。脆弱なので scram に移行すべき
peerOS ユーザー名と一致 (local 専用)
certクライアント証明書のみ
gss / sspiKerberos / Windows SSPI
ldap / radius / pam外部認証サーバ
identidentd プロトコル (古い)
列⑥ OPTIONS — 認証方式のオプション

METHOD によって追加オプションが指定できます。例: map=usermap1 (pg_ident でマッピング)、clientcert=verify-full (証明書検証)、ldapserver=ldap.example.com (LDAP サーバ)。

評価ルール (重要)

① 上から順に評価、② TYPE + DATABASE + USER + ADDRESS がすべて一致した行が採用、 ③ METHOD が reject なら拒否、④ パスワード認証なら入力を検証して可否決定。 ⑤ 一度マッチしたら後続の行は評価されない — 弱いルールが上にあると強いルールが死ぬので注意。

本番推奨テンプレ
# ── 1. ローカル管理用 (peer = OS user 一致)
local   all            postgres                              peer

# ── 2. アプリケーション接続 (SSL 必須 + scram)
hostssl mydb           app_user      10.0.0.0/8            scram-sha-256

# ── 3. レプリケーション (専用ユーザー)
hostssl replication    replicator    10.0.1.0/24           scram-sha-256

# ── 4. 読み取り専用ロール
hostssl all            +readonly     10.0.0.0/8            scram-sha-256

# ── 5. 非 SSL を明示的に拒否 (フォールバック)
hostnossl all          all           0.0.0.0/0             reject

# ── 6. それ以外も拒否 (デフォルト)
host    all            all           0.0.0.0/0             reject

pg_ident.conf

OS ユーザー名と PostgreSQL ロール名のマッピング表peer / cert / gss / ldap 認証で、 外部から渡される「ユーザー名」を PG 内の「ロール名」へ変換する時に使います。

単独では機能せず、pg_hba.conf の OPTIONS で map=マップ名 を指定して初めて有効になります。 ファイル場所は SHOW ident_file; で確認可能。

典型例 — OS ユーザー mapping
# pg_ident.conf
# MAPNAME       SYSTEM-USERNAME    PG-USERNAME

# OS ユーザー deploy → PG ロール app_user として認証可
deploy_map      deploy             app_user

# 複数の OS ユーザーを 1 つの PG ロールに集約
analyst_map     alice              analyst
analyst_map     bob                analyst
analyst_map     carol              analyst

# 正規表現も可 (PG-USERNAME の \1 で参照)
regex_map       /^(.*)@example\.com$    \1
pg_hba.conf 側の対応
# pg_hba.conf 側でマップ名を参照
local   all   all                  peer    map=deploy_map
hostssl all   +analysts  10/8      cert    map=analyst_map
使う場面
OS ユーザー名 ≠ DB ロール名deploy という OS アカウントが app_user として接続したい場合
複数 OS ユーザーを共通ロールにまとめるチームメンバー全員を 1 つの analyst ロールへ集約
AD / Kerberos 統合認証username@DOMAIN を PG ロール名へ正規表現マッピング
クライアント証明書認証証明書の CN を PG ロールに対応付け
OS 統合認証を使わないなら不要:scram-sha-256 のパスワード認証のみで運用するなら、pg_ident.conf を触る必要はありません (空ファイルでも OK)。 peer / cert / gss / ldap 認証を使う環境でのみ意識すれば十分です。

postgresql.auto.conf

ALTER SYSTEM コマンドが自動で読み書きする設定ファイル。 手で編集してはいけません。SQL 経由でしか書き換えない代わりに、postgresql.conf より後に読まれて優先されるので、本番で動的に設定を変える時の正規ルートになります。

ファイル場所は data_directory 直下 (/var/lib/postgresql/16/main/postgresql.auto.conf など)。 PG 起動時に postgresql.conf → postgresql.auto.conf の順で読まれるため、両方で同じパラメータが設定されている場合は auto.conf が勝ちます。

ALTER SYSTEM コマンド
-- 設定変更 (auto.conf に書き込み)
ALTER SYSTEM SET work_mem = '128MB';

-- reload で適用 (context が sighup なら即反映)
SELECT pg_reload_conf();

-- 確認
SHOW work_mem;
SELECT name, setting, source, context FROM pg_settings
WHERE name = 'work_mem';

-- リセット (auto.conf から削除 → postgresql.conf の値に戻る)
ALTER SYSTEM RESET work_mem;

-- 全リセット
ALTER SYSTEM RESET ALL;

-- ファイル中身を見る
\! cat /var/lib/postgresql/16/main/postgresql.auto.conf

設定スコープの SET

-- セッション内
SET work_mem = '256MB';

-- トランザクション内のみ (推奨)
BEGIN;
  SET LOCAL work_mem = '256MB';
  -- 重い集計クエリ
COMMIT;
-- ↑ COMMIT した瞬間に元の値に戻る (PgBouncer の transaction モードでも安全)

-- 特定ロールに永続
ALTER ROLE analyst SET work_mem = '512MB';

-- 特定 DB に永続
ALTER DATABASE warehouse SET work_mem = '256MB';

-- 特定ロール × 特定 DB
ALTER ROLE analyst IN DATABASE warehouse SET work_mem = '1GB';

設定確認 — pg_settings ビューと SHOW

-- シンプル確認
SHOW shared_buffers;
SHOW all;

-- 詳細 (どこから値が来たか分かる)
SELECT name, setting, unit, source, sourcefile, sourceline, context, pending_restart
FROM pg_settings
WHERE name IN ('shared_buffers', 'work_mem', 'max_connections');

-- 再起動が必要な保留中の変更
SELECT name, setting, pending_restart FROM pg_settings WHERE pending_restart;

-- カテゴリ別に見る
SELECT category, name, setting FROM pg_settings WHERE category LIKE '%Replication%';

-- ファイル一覧
SELECT * FROM pg_file_settings;

reload と restart — 設定を反映する 2 つの方法

設定ファイルを書き換えても、それだけでは動いている PostgreSQL には伝わりません。 反映させるには reload (再読込)restart (再起動) のどちらかが必要で、 パラメータごとに「どちらが必要か」が決まっています。これを決めているのが context という属性です。

context とは:各パラメータが「いつ反映されるか」を表す PostgreSQL のメタデータです。SELECT name, context FROM pg_settings; で確認できます。 値は以下の 6 種類です。

internal
変更不可
コンパイル時に固定 (例: block_size)
postmaster
再起動が必要
共有メモリの量・プロセス構成が変わるもの。shared_buffers / max_connections / wal_level など
sighup
reload で反映
全プロセス共通の設定で動的に変えられるもの。log_* / autovacuum_* / archive_* など
superuser-backend
reload で反映 (新規接続のみ)
接続確立時に決まる設定。既存セッションには適用されない
backend
reload で反映 (新規接続のみ)
ユーザー権限で接続時に変えられる設定
superuser / user
SET で即時 (セッション単位)
SET / SET LOCAL でその場で変えられるもの。work_mem / statement_timeout など
① pg_ctl reload (SIGHUP)
何をしているか: Postmaster に SIGHUP シグナルを送り「設定を読み直して」と指示するだけ。プロセスは終了しません。 Postmaster は postgresql.conf を再パースして、子プロセス全員に新しい値を配ります。

適用される context: sighup / backend / superuser / user
ダウンタイム: 0 秒。既存セッションも保持されます。
適用例: work_mem / log_min_duration_statement / autovacuum_naptime / archive_command / pg_hba.conf 全体

コマンド (どれでも OK):
pg_ctl reload
systemctl reload postgresql
SELECT pg_reload_conf(); (SQL からも可)
② pg_ctl restart
何をしているか: Postmaster ごとプロセスを終了 → 再起動。共有メモリも全部作り直し、すべての子プロセスを fork し直します。

適用される context: postmaster
ダウンタイム: 通常 5〜30 秒。WAL リプレイがあれば数分。
影響: 全クライアント接続が切断される。アプリ側に再接続ロジックが必須。
適用例: shared_buffers / max_connections / max_wal_senders / wal_level / port / listen_addresses / shared_preload_libraries

本番での進め方: ① 事前に pg_settings.pending_restart = true で「再起動待ち」のパラメータを確認 → ② Streaming Replica にフェイルオーバー → ③ Primary を restart → ④ Replica に戻す、の手順で実質ダウンタイム数秒に抑えるのが定石です。

コマンド:
pg_ctl restart -m fast
systemctl restart postgresql

判断フロー: ① パラメータを ALTER SYSTEM か postgresql.conf で変更 → ② SELECT context FROM pg_settings WHERE name = '...'; で確認 → ③ postmaster なら restart、それ以外は reload。 わからない時はとりあえず reload して、SELECT name, pending_restart FROM pg_settings WHERE pending_restart; で「再起動が必要なまま残っているもの」を見つけるのが安全です。

よくある罠: ① reload しか打たず shared_buffers 等を変更した気でいる → pending_restart=true のまま放置される。 ② postgresql.auto.confpostgresql.conf の両方に同じ設定があり、auto.conf が勝って意図と違う値で動いている。 ③ pg_hba.conf を編集したのに reload を忘れて「認証が変わらない」と悩む。

include で設定ファイルを分割

# postgresql.conf 内で他ファイルを include 可能

include = '/etc/postgresql/16/main/memory.conf'
include = '/etc/postgresql/16/main/wal.conf'

# ディレクトリ全体を読み込み (推奨パターン)
include_dir = '/etc/postgresql/16/main/conf.d/'

# 環境毎に分けると管理しやすい
#   conf.d/00-base.conf
#   conf.d/10-memory.conf
#   conf.d/20-replication.conf
#   conf.d/90-overrides.conf  ← この順で後勝ち

ALTER SYSTEM / SET / RESET / pg_reload_conf() — 設定変更コマンド完全ガイド

設定ファイルを直接編集しなくても、SQL コマンドで動的にパラメータを変更できます。スコープ (適用範囲) によって使うコマンドが違うので、それぞれの構文と影響範囲を正確に押さえます。

ALTER SYSTEM SET param = value;
スコープ: クラスタ全体・永続
postgresql.auto.conf に書き込み、PG 再起動後も保持。実際には pg_reload_conf() で反映 (context = sighup の場合) または再起動が必要 (context = postmaster)。手でファイル編集する代わりにこちらを使うのが現代的。
ALTER SYSTEM RESET param;
スコープ: クラスタ全体・永続
auto.conf から該当行を削除。postgresql.conf 側の値に戻る。
ALTER SYSTEM RESET ALL;
スコープ: クラスタ全体・永続
auto.conf を完全クリア。「手動で auto.conf をいじって壊した」時の回復手段。
ALTER DATABASE name SET param = value;
スコープ: DB 単位・永続
特定 DB への接続時のみ適用される。分析用 DB だけ work_mem を大きくする等。
ALTER ROLE name SET param = value;
スコープ: ロール単位・永続
特定ロールでログインした時のみ適用。analyst ロールだけ statement_timeout を伸ばす等。
ALTER ROLE name IN DATABASE db SET param = value;
スコープ: ロール × DB 単位
特定ロール + 特定 DB の組み合わせ。ALTER DATABASE と ALTER ROLE の両方を兼ねる。
SET param = value;
スコープ: セッション単位・揮発
現在のセッションのみ。接続切断で消える。一時的な調査や手動チューニング用。
SET LOCAL param = value;
スコープ: トランザクション単位・揮発
現在のトランザクション内のみ。COMMIT/ROLLBACK で元に戻る。重い集計クエリだけ work_mem を一時的に上げる等の安全な使い方。
SET SESSION CHARACTERISTICS AS ...;
スコープ: セッション単位・揮発
トランザクション特性 (isolation, read only 等) のセッションデフォルトを変更。
RESET param;
スコープ: セッション単位
SET で変更した値をデフォルトに戻す。
RESET ALL;
スコープ: セッション単位
セッション内で SET した全パラメータをリセット。
SHOW param;
スコープ: 参照のみ
現在のセッションでの値を表示。SHOW ALL で全パラメータ。
SHOW shared_buffers;
スコープ: 参照のみ
個別パラメータの確認。SELECT current_setting('shared_buffers') でも同じ。
SELECT pg_reload_conf();
スコープ: 関数呼び出し
SIGHUP を Postmaster に送って設定ファイルを再読み込みさせる。pg_ctl reload と同じ効果。context = sighup のパラメータが反映される。
SELECT pg_settings.*;
スコープ: 参照のみ
SELECT * FROM pg_settings WHERE name = 'work_mem' でパラメータの詳細情報 (現在値・デフォルト・context・上書き元) が見える。
SELECT pg_file_settings.*;
スコープ: 参照のみ
設定ファイルから読み込まれた全行を表示。どのファイルのどの行から来ているかが分かる。設定が効かない時のデバッグに有用。

実運用での組み合わせ例:

-- ① 永続的な設定変更 (SQL で完結、ファイル編集不要)
ALTER SYSTEM SET work_mem = '128MB';
SELECT pg_reload_conf();  -- 反映 (context = sighup なので reload で OK)
SHOW work_mem;            -- 確認

-- ② 再起動が必要なパラメータ (context = postmaster)
ALTER SYSTEM SET shared_buffers = '8GB';
SELECT pg_reload_conf();  -- これだけでは反映しない
-- pending_restart で未反映を確認
SELECT name, setting, pending_restart FROM pg_settings WHERE pending_restart;
-- → サーバ再起動が必要

-- ③ 重いバッチクエリで一時的に work_mem を上げる (安全パターン)
BEGIN;
  SET LOCAL work_mem = '512MB';
  -- 重い集計クエリ
COMMIT;  -- 自動で元に戻る (PgBouncer transaction mode でも安全)

-- ④ analyst ロールだけ statement_timeout を緩める
ALTER ROLE analyst SET statement_timeout = '30min';
ALTER ROLE analyst SET work_mem = '512MB';

-- ⑤ 分析用 DB だけメモリ設定を変える
ALTER DATABASE warehouse SET work_mem = '256MB';
ALTER DATABASE warehouse SET random_page_cost = 1.1;

-- ⑥ 設定の追跡 (どこから来ているか)
SELECT name, setting, unit, source, sourcefile, sourceline, context
FROM pg_settings
WHERE name IN ('work_mem', 'shared_buffers', 'statement_timeout');

-- ⑦ ファイルから読み込まれた行を確認 (構文エラー検出にも)
SELECT * FROM pg_file_settings WHERE NOT applied;
-- applied = false の行は構文エラーなどで読み込み失敗

-- ⑧ ALTER SYSTEM の取り消し (auto.conf からの削除)
ALTER SYSTEM RESET work_mem;
SELECT pg_reload_conf();

-- ⑨ 全 ALTER SYSTEM 設定をクリア (auto.conf 完全削除)
ALTER SYSTEM RESET ALL;
SELECT pg_reload_conf();

-- ⑩ シェルから (psql 経由でないと打ちにくいので)
-- $ pg_ctl reload                  -- 設定再読込
-- $ pg_ctl restart -m fast         -- 再起動
-- $ systemctl reload postgresql    -- systemd 環境

ALTER SYSTEM の落とし穴: ① ALTER SYSTEM はpostgresql.auto.conf に書くだけで反映はしない。必ず pg_reload_conf() か再起動が必要、② postgresql.auto.conf手で編集してはいけない (ALTER SYSTEM が管理する領域なので整合性が崩れる)、③ postgresql.conf より auto.conf の値が常に優先される (リロードの順序)。

設定ファイル運用のベストプラクティス:① 全ファイルを Git で管理、② 環境差分は include_dir で分割、③ 値の理由をコメントで残す、 ④ 大幅変更はステージングで pg_reload_conf → 動作確認、⑤ pgtune.leopard.in.ua や Postgres Cluster Cookbook を参考に。
postgresql.auto.conf を手で編集しない:ALTER SYSTEM の管理外になり整合性が崩れます。動的に変えたいなら ALTER SYSTEM、静的なベースラインは postgresql.conf、と役割分担を厳守してください。
─ PREMIUM ─

ここから先はプレミアム会員限定

テーブル設計・MVCC・WAL・インデックス・実行計画・チューニング・パーティショニング・レプリケーション・バックアップ・セキュリティまで、PostgreSQL の中身を本気で理解するための全要素はプレミアムプランで読めます。

プレミアムを見る
PostgreSQL 完全攻略 | Vizigo