DBAtlas · データベース運用アトラス

月次のレンジパーティション表を作成(ループでパーティションを生成)

PostgreSQLパーティション化

コマンド

CREATE TABLE sales (
  id         bigint GENERATED ALWAYS AS IDENTITY,
  created_at      date   NOT NULL,
  customer_id bigint NOT NULL,
  amount      numeric(12,2),
  PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);

-- An index defined on the parent propagates to all partitions automatically
CREATE INDEX sales_customer_id_idx ON sales (customer_id);

-- 12 monthly partitions for 2026
DO $$
DECLARE
  m date;
BEGIN
  FOR m IN SELECT generate_series(date '2026-01-01', date '2026-12-01', interval '1 month')::date LOOP
    EXECUTE format(
      'CREATE TABLE IF NOT EXISTS %I PARTITION OF sales FOR VALUES FROM (%L) TO (%L)',
      'sales_' || to_char(m, 'YYYY_MM'), m, (m + interval '1 month')::date);
  END LOOP;
END $$;

-- Hierarchy, bounds and sizes
SELECT t.relid::regclass AS partition_name,
       t.parentrelid::regclass AS parent,
       t.isleaf,
       t.level,
       pg_get_expr(c.relpartbound, c.oid) AS bounds,
       pg_size_pretty(pg_total_relation_size(t.relid)) AS total_size
FROM pg_partition_tree('sales') t
JOIN pg_class c ON c.oid = t.relid
ORDER BY t.level, bounds;

概要

日付列でRANGEパーティション化された親表、すべてのパーティションに伝播するインデックス、ループで12の月次パーティションを作成する。その後、境界とサイズとともに階層を一覧表示する。

使用する場面

古いデータを定期的に削除する(DETACH/DROP)、またはクエリの大部分が日付範囲でフィルタする、増え続ける大きな表(注文、ログ、時系列)に。

注意

パーティション表では、PRIMARY KEY/UNIQUE制約にパーティションキーを含める必要がある(グローバルな一意インデックスは存在しない)。下限は含み、上限は含まない(FROMは含む、TOは含まない)。将来のパーティションを事前作成するジョブ(pg_cron、pg_partman)がないと、範囲外のINSERTは失敗する。数千のパーティションは計画時間とロックのオーバーヘッドを増加させる。親表ではCREATE INDEX CONCURRENTLYはサポートされない: 親でCREATE INDEX ... ON ONLY、各パーティションでCREATE INDEX CONCURRENTLYを実行し、その後ALTER INDEX ... ATTACH PARTITIONを使用する。

DBAtlas で開く →

関連項目