DBAtlas · 데이터베이스 운영 아틀라스

월별 range 파티션 테이블 생성(루프로 파티션 생성)

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 제약 조건은 파티션 키를 포함해야 한다(전역 unique 인덱스가 없다). 하한은 포함, 상한은 제외다(FROM 포함, TO 제외). 미래 파티션을 미리 만드는 job(pg_cron, pg_partman)이 없으면 범위를 벗어난 INSERT가 실패한다. 파티션이 수천 개면 계획 시간과 락 오버헤드가 늘어난다. 부모에서는 CREATE INDEX CONCURRENTLY가 지원되지 않는다. 부모에 CREATE INDEX ... ON ONLY, 각 파티션에 CREATE INDEX CONCURRENTLY를 실행한 후 ALTER INDEX ... ATTACH PARTITION을 사용한다.

DBAtlas에서 열기 →

관련 항목