pg_partman + pg_cron パーティション運用ガイド
1. 概要
本ドキュメントでは、pg_partmanとpg_cronを使用したPostgreSQLパーティションの自動運用について説明します。
1.1 pg_partman とは
pg_partmanは、PostgreSQLのパーティション管理を自動化する拡張機能です。
┌─────────────────────────────────────────────────────────────────────────────┐
│ pg_partman の役割 │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────── ──────┐ │
│ │ パーティション │ │ パーティション │ │ 保持ポリシー │ │
│ │ 自動作成 │ │ 自動削除 │ │ 管理 │ │
│ │ (premake) │ │ (retention) │ │ │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ 手動でのCREATE TABLE / DROP TABLEが不要になる │
└─────────────────────────────────────────────────────────────────────────────┘
1.2 pg_cron とは
pg_cronは、PostgreSQL内でジョブをスケジュール実行するための拡張機能です。
-- cron式でSQLを定期実行
SELECT cron.schedule('job-name', '0 * * * *', 'SELECT my_function();');
1.3 なぜこの組み合わせか
| 方式 | メリット | デメリット | AWS RDS対応 |
|---|---|---|---|
| 手動パーティション管理 | シンプル | 運用負荷高い | ✅ |
| pg_partman + pg_partman_bgw | 設定のみで自動化 | - | ❌ |
| pg_partman + pg_cron | 柔軟なスケジュール | - | ✅ |
| 外部スケジューラー(Lambda等) | AWS連携容易 | 複雑 | ✅ |
AWS RDSではpg_partman_bgwが使用できないため、pg_cronとの組み合わせが推奨されます。
2. 環境構成
2.1 ローカル開発環境(Docker)
# docker-compose.yaml
postgres-primary:
command: [
"postgres",
"-c", "shared_preload_libraries=pg_stat_statements,pg_cron",
"-c", "cron.database_name=idpserver"
]
2.2 AWS RDS
# パラメータグループ設定
shared_preload_libraries = 'pg_cron'
cron.database_name = 'idpserver'
注意: パラメータグループ変更後はDBインスタンスの再起動が必要です。
3. セットアップ手順
3.1 拡張機能の有効化
-- pg_cronの有効化
CREATE EXTENSION IF NOT EXISTS pg_cron;
-- pg_partmanの有効化
CREATE SCHEMA IF NOT EXISTS partman;
CREATE EXTENSION IF NOT EXISTS pg_partman WITH SCHEMA partman;
3.2 パーティションテーブルの作成
-- 例: 統計ユーザーテーブル(日別パーティション)
CREATE TABLE statistics_daily_users (
tenant_id UUID NOT NULL,
stat_date DATE NOT NULL,
user_id UUID NOT NULL,
last_used_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (tenant_id, stat_date, user_id)
) PARTITION BY RANGE (stat_date);
CREATE INDEX idx_daily_users_tenant_date
ON statistics_daily_users(tenant_id, stat_date);
3.3 pg_partman設定
-- パーティション管理を設定
SELECT partman.create_parent(
p_parent_table => 'public.statistics_daily_users',
p_control => 'stat_date', -- パーティションキー
p_type => 'range', -- RANGE パーティション
p_interval => '1 month', -- 月別パーティション
p_premake => 3, -- 3ヶ月先まで事前作成
p_start_partition => '2024-01-01' -- 開始日
);
-- 保持ポリシー設定
UPDATE partman.part_config
SET infinite_time_partitions = true, -- 無限に新規作成
retention = '6 months', -- 6ヶ月保持
retention_keep_table = false, -- 古いパーティションを削除
retention_keep_index = false -- インデックスも削除
WHERE parent_table = 'public.statistics_daily_users';
3.4 pg_cronでメンテナンスジョブを設定
-- 毎時メンテナンス実行(推奨)
SELECT cron.schedule(
'partman-maintenance',
'0 * * * *', -- 毎時0分
$$CALL partman.run_maintenance_proc()$$
);
-- または毎日AM2時に実行
SELECT cron.schedule(
'partman-daily-maintenance',
'0 2 * * *', -- 毎日AM2:00
$$CALL partman.run_maintenance_proc()$$
);
4. 推奨設定
4.1 統計データテーブルの設定
| テーブル | パーティション間隔 | premake | 保持期間 |
|---|---|---|---|
statistics_daily_users | 月別 | 3 | 6ヶ月 |
statistics_monthly_users | 年別 | 2 | 3年 |
statistics_yearly_users | 年別 | 2 | 5年 |
4.2 設定例
-- DAU(日次アクティブユーザー)テーブル
SELECT partman.create_parent(
p_parent_table => 'public.statistics_daily_users',
p_control => 'stat_date',
p_type => 'range',
p_interval => '1 month',
p_premake => 3,
p_start_partition => '2024-01-01'
);
UPDATE partman.part_config
SET retention = '6 months',
retention_keep_table = false
WHERE parent_table = 'public.statistics_daily_users';
-- MAU(月次アクティブユーザー)テーブル
SELECT partman.create_parent(
p_parent_table => 'public.statistics_monthly_users',
p_control => 'stat_month',
p_type => 'range',
p_interval => '1 year',
p_premake => 2,
p_start_partition => '2024-01-01'
);
UPDATE partman.part_config
SET retention = '3 years',
retention_keep_table = false
WHERE parent_table = 'public.statistics_monthly_users';
-- YAU(年次アクティブユーザー)テーブル
SELECT partman.create_parent(
p_parent_table => 'public.statistics_yearly_users',
p_control => 'stat_year',
p_type => 'range',
p_interval => '1 year',
p_premake => 2,
p_start_partition => '2024-01-01'
);
UPDATE partman.part_config
SET retention = '5 years',
retention_keep_table = false
WHERE parent_table = 'public.statistics_yearly_users';
5. 運用監視
5.1 pg_partman設定確認
-- 設定一覧
SELECT
parent_table,
partition_interval,
premake,
retention,
infinite_time_partitions as infinite
FROM partman.part_config
ORDER BY parent_table;
5.2 パーティション一覧確認
-- 特定テーブルのパーティション一覧
SELECT
c.relname as partition,
pg_size_pretty(pg_relation_size(c.oid)) as size
FROM pg_inherits i
JOIN pg_class c ON i.inhrelid = c.oid
JOIN pg_class p ON i.inhparent = p.oid
WHERE p.relname = 'statistics_daily_users'
ORDER BY c.relname;