PostgreSQL 拡張機能(Extensions)ガイド
PostgreSQLは拡張機能(Extension)によって機能を追加でき ます。 本ドキュメントでは、実運用でよく使われる拡張機能を解説します。
目次
- 拡張機能の基本操作
- パフォーマンス・監視系
- メンテナンス系
- スケジューリング系
- セキュリティ・暗号化系
- データ型・検索拡張系
- 地理情報系
- 外部データ連携系
- 8.1 postgres_fdw
- 8.2 file_fdw
- 8.3 aws_commons(RDS専用)
- 8.4 aws_s3(RDS専用)
- 8.5 aws_lambda(RDS専用)
- 拡張機能の管理ベストプラクティス
1. 拡張機能の基本操作
1.1 拡張機能の概念
┌─────────────────────────────────────────────────────────────────┐
│ PostgreSQL 拡張機能 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 【拡張機能とは】 │
│ PostgreSQLの機能を拡張するパッケージ │
│ ・新しいデータ型 │
│ ・新しい関数/演算子 │
│ ・新しいインデックスタイプ │
│ ・バックグラウンドワーカー │
│ │
│ 【提供形態】 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ contrib: PostgreSQL本体に同梱 │ │
│ │ 例: pg_stat_statements, pgcrypto, uuid-ossp │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ 外部: 別途インストールが必要 │ │
│ │ 例: PostGIS, pg_partman, pg_cron, pgaudit │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
1.2 基本コマンド
-- 利用可能な拡張機能の一覧
SELECT * FROM pg_available_extensions ORDER BY name;
-- インストール済み拡張機能の一覧
SELECT extname, extversion FROM pg_extension ORDER BY extname;
-- 拡張機能のインストール
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- 特定スキーマにインストール
CREATE EXTENSION pg_stat_statements WITH SCHEMA public;
-- 拡張機能のアップグレード
ALTER EXTENSION pg_stat_statements UPDATE;
-- 特定バージョンへアップグレード
ALTER EXTENSION pg_stat_statements UPDATE TO '1.10';
-- 拡張機能の削除
DROP EXTENSION pg_stat_statements;
-- 依存関係も含めて削除
DROP EXTENSION pg_stat_statements CASCADE;
1.3 shared_preload_libraries
一部の拡張機能はサーバー起動時にロードが必要です。
# postgresql.conf
# カンマ区切りで複数指定可能
shared_preload_libraries = 'pg_stat_statements, pg_cron, pgaudit'
┌─────────────────────────────────────────────────────────────────┐
│ shared_preload_libraries が必要な拡張機能 │
├────────────────────────────────────────────────────── ───────────┤
│ │
│ 【必須】 │
│ ・pg_stat_statements - クエリ統計収集 │
│ ・pg_cron - ジョブスケジューラ │
│ ・pgaudit - 監査ログ │
│ ・auto_explain - 自動EXPLAIN出力 │
│ ・pg_prewarm - バッファキャッシュウォームアップ │
│ │
│ 【不要】 │
│ ・pgcrypto - 暗号化関数 │
│ ・uuid-ossp - UUID生成 │
│ ・pg_trgm - 類似検索 │
│ ・hstore - キーバリュー型 │
│ ・PostGIS - 地理情報 │
│ │
│ 【注意】 │
│ shared_preload_librariesの変更後は再起動が必要 │
│ │
└─────────────────────────────────────────────────────────────────┘
shared_preload_libraries が必要になる技術的基準
なぜ一部の拡張機能だけがサーバー起動時のロードを必要とするのか、 その技術的な理由は以下の3つの条件に集約されます。
┌─────────────────────────────────────────────────────────────────┐
│ shared_preload_libraries が必要な技術的理由 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 【条件1】共有メモリを確保する必要がある │
│ ┌─────── ──────────────────────────────────────────────────┐ │
│ │ PostgreSQLの共有メモリはサーバー起動時に確保される │ │
│ │ → 後から動的に追加できない │ │
│ │ │ │
│ │ 例: pg_stat_statements │ │
│ │ クエリ統計を保存する領域を共有メモリに確保 │ │
│ │ pg_stat_statements.max = 10000 → その分のメモリ確保 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 【条件2】フック(Hook)を登録する必要がある │
│ ┌─────────────────────────────── ──────────────────────────┐ │
│ │ PostgreSQLは各処理ポイントにフック機構を提供 │ │
│ │ フックはサーバー起動時に登録する必要がある │ │
│ │ │ │
│ │ 主なフックポイント: │ │
│ │ ・ExecutorStart_hook - クエリ実行開始時 │ │
│ │ ・ExecutorEnd_hook - クエリ実行完了時 │ │
│ │ ・ProcessUtility_hook - DDL/ユーティリティ実行時 │ │
│ │ ・planner_hook - クエリプラン作成時 │ │
│ │ │ │
│ │ 例: pg_stat_statements │ │
│ │ ExecutorEnd_hook → クエリ完了時に統計記録 │ │
│ │ │ │
│ │ 例: auto_explain │ │
│ │ ExecutorEnd_hook → クエリ完了時に実行計画出力 │ │
│ │ │ │
│ │ 例: pgaudit │ │
│ │ ProcessUtility_hook → DDL実行時に監査ログ出力 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 【条件3】バックグラウンドワーカーを起動する必要がある │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 常駐プロセスとして動 作する機能 │ │
│ │ → サーバー起動時にワーカーを登録・起動 │ │
│ │ │ │
│ │ 例: pg_cron │ │
│ │ スケジューラとして常駐し、定期的にジョブを実行 │ │
│ │ │ │
│ │ 例: pg_prewarm (autoprewarm) │ │
│ │ 定期的にバッファ状態を保存するワーカー │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
shared_preload_libraries が不要な拡張機能の特徴
┌─────────────────────────────────────────────────────────────────┐
│ shared_preload_libraries が不要な拡張機能 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 【特徴】セッション単位で動作し、グローバルな状態を持たない │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ・新しい関数を提供するだけ │ │
│ │ pgcrypto: crypt(), encrypt() など │ │
│ │ uuid-ossp: uuid_generate_v4() など │ │
│ │ │ │
│ │ ・新しいデータ型を提供するだけ │ │
│ │ hstore: キーバリュー型 │ │
│ │ ltree: 階層パス型 │ │
│ │ PostGIS: geometry, geography型 │ │
│ │ │ │
│ │ ・新しい演算子/インデックスを提供するだけ │ │
│ │ pg_trgm: %, <-> 演算子、GINインデックス │ │
│ │ │ │
│ │ これらは CREATE EXTENSION 時に │ │
│ │ システムカタログ(pg_proc, pg_type等)に登録されるだけ │ │
│ │ → 実行時にオンデマンドでロードされる │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└────────────────── ───────────────────────────────────────────────┘
判断フローチャート
拡張機能の機能は?
│
┌───────────────┼───────────────┐
▼ ▼ ▼
共有メモリが フック登録が バックグラウンド
必要? 必要? ワーカーが必要?
│ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
Yes No Yes No Yes No
│ │ │ │ │ │
▼ │ ▼ │ ▼ │
必要 ────────┴───→ 必要 ─────┴───→ 必要 │
│
▼
┌───────────────────┴───────────────────┐
│ すべてNoの場合 │
│ → shared_preload_libraries 不要 │
│ → CREATE EXTENSION だけでOK │
└───────────────────────────────────────┘
拡張機能別の分類一覧
| 拡張機能 | 共有メモリ | フック | BGワーカー | 必要? |
|---|---|---|---|---|
| pg_stat_statements | ✅ | ✅ | - | 必要 |
| pgaudit | - | ✅ | - | 必要 |
| auto_explain | - | ✅ | - | 必要 |
| pg_cron | ✅ | - | ✅ | 必要 |
| pg_prewarm (auto) | ✅ | - | ✅ | 必要 |
| pgcrypto | - | - | - | 不要 |
| uuid-ossp | - | - | - | 不要 |
| pg_trgm | - | - | - | 不要 |
| hstore | - | - | - | 不要 |
| PostGIS | - | - | - | 不要 |
| pg_repack | - | - | - | 不要 |
| pg_partman | - | - | ※ | ※条件付き |
※ pg_partman: pg_partman_bgwをバックグラウンドワーカーとして使う場合のみ必要。
pg_cronと連携して定期 実行する場合は不要。
2. パフォーマンス・監視系
2.1 pg_stat_statements
最も重要な拡張機能の一つ。クエリの実行統計を収集します。
┌─────────────────────────────────────────────────────────────────┐
│ pg_stat_statements │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 【機能】 │
│ ・実行されたSQLの統計情報を収集 │
│ ・実行回数、合計時間、平均時間、行数などを記録 │
│ ・クエリを正規化(パラメータを$1, $2に置換) │
│ │
│ 【ユースケース】 │
│ ・スロークエリの特定 │
│ ・最も頻繁に実行されるクエリの特定 │
│ ・リソース消費の大きいクエリの特定 │
│ ・クエリパフォーマンスの経時変化監視 │
│ │
└──────────────────────────────────────── ─────────────────────────┘
設定
# postgresql.conf
shared_preload_libraries = 'pg_stat_statements'
# 追跡するクエリ数(デフォルト: 5000)
pg_stat_statements.max = 10000
# 追跡対象(all/top/none)
pg_stat_statements.track = all
# ネストした関数呼び出しも追跡
pg_stat_statements.track_utility = on
# WAL使用量も追跡(PostgreSQL 13+)
pg_stat_statements.track_wal = on
使用例
-- インストール
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- 総実行時間が長いクエリTOP10
SELECT
substring(query, 1, 80) AS query_preview,
calls,
round(total_exec_time::numeric, 2) AS total_time_ms,
round(mean_exec_time::numeric, 2) AS avg_time_ms,
round((100 * total_exec_time / sum(total_exec_time) OVER ())::numeric, 2) AS percentage,
rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
-- 平均実行時間が長いクエリTOP10
SELECT
substring(query, 1, 80) AS query_preview,
calls,
round(mean_exec_time::numeric, 2) AS avg_time_ms,
round(stddev_exec_time::numeric, 2) AS stddev_ms,
rows / nullif(calls, 0) AS avg_rows
FROM pg_stat_statements
WHERE calls > 100 -- 十分な実行回数があるもの
ORDER BY mean_exec_time DESC
LIMIT 10;
-- 実行回数が多いクエリTOP10
SELECT
substring(query, 1, 80) AS query_preview,
calls,
round(total_exec_time::numeric, 2) AS total_time_ms,
round(mean_exec_time::numeric, 2) AS avg_time_ms
FROM pg_stat_statements
ORDER BY calls DESC
LIMIT 10;
-- I/O時間が長いクエリ(PostgreSQL 13+)
SELECT
substring(query, 1, 80) AS query_preview,
calls,
round(blk_read_time::numeric, 2) AS read_time_ms,
round(blk_write_time::numeric, 2) AS write_time_ms,
shared_blks_read,
shared_blks_hit
FROM pg_stat_statements
WHERE blk_read_time > 0
ORDER BY blk_read_time DESC
LIMIT 10;
-- 統計のリセット
SELECT pg_stat_statements_reset();
-- 特定ユーザーの統計のみリセット
SELECT pg_stat_statements_reset(userid := (SELECT oid FROM pg_roles WHERE rolname = 'app_user'));
2.2 pg_buffercache
共有バッファの内容を可視化します。
-- インストール
CREATE EXTENSION IF NOT EXISTS pg_buffercache;
-- テーブル別のバッファ使用量
SELECT
c.relname AS table_name,
count(*) AS buffers,
pg_size_pretty(count(*) * 8192) AS buffer_size,
round(100.0 * count(*) / (SELECT count(*) FROM pg_buffercache), 2) AS percentage
FROM pg_buffercache b
JOIN pg_class c ON b.relfilenode = pg_relation_filenode(c.oid)
WHERE c.relkind IN ('r', 'i') -- テーブルとインデックス
GROUP BY c.relname
ORDER BY buffers DESC
LIMIT 20;
-- バッファのダーティ率
SELECT
count(*) FILTER (WHERE isdirty) AS dirty_buffers,
count(*) AS total_buffers,
round(100.0 * count(*) FILTER (WHERE isdirty) / count(*), 2) AS dirty_percentage
FROM pg_buffercache
WHERE relfilenode IS NOT NULL;