Quick Comparison
| 방식 | 기준 | 대표 사용 |
|---|---|---|
| Range partition | 날짜, 숫자 범위 | 월별 로그, 주문 |
| List partition | 명시 값 목록 | 지역, tenant, 상태 |
| Hash partition | hash 나머지 | 균등 분산 |
CREATE TABLE events (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
occurred_at TIMESTAMPTZ NOT NULL,
payload JSONB NOT NULL,
PRIMARY KEY (occurred_at, id)
) PARTITION BY RANGE (occurred_at);
CREATE TABLE events_2026_05
PARTITION OF events
FOR VALUES FROM (TIMESTAMPTZ '2026-05-01 00:00:00+00')
TO (TIMESTAMPTZ '2026-06-01 00:00:00+00');partitioning은 partition key가 대부분의 큰 query와 데이터 수명 주기를 가를 때만 검토합니다. 시간 범위 삭제·detach가 핵심이면 range, 값별 분리가 핵심이면 list, 키 분산이 핵심이면 hash를 고릅니다. parent의 PRIMARY KEY·UNIQUE는 모든 partition key를 포함해야 하며, 새 partition attach·default partition 검증의 lock과 scan 비용까지 운영 계획에 넣어야 합니다.
구조
partitioning은 논리적으로 하나의 큰 테이블을 여러 물리 테이블로 나누는 방식입니다. 부모 테이블은 구조와 라우팅 기준을 정의하고, 실제 행은 조건에 맞는 partition에 저장됩니다.
events
├─ events_2026_05
├─ events_2026_06
└─ events_2026_07날짜 기준 로그처럼 오래된 데이터와 최신 데이터의 접근 패턴이 명확히 다르면 partition이 운영에 도움이 됩니다. 예를 들어 오래된 월 partition을 통째로 detach하거나 drop하면 대량 DELETE보다 훨씬 빠르고 vacuum 부담도 줄어듭니다.
Partition pruning
partition pruning은 쿼리 조건으로 읽을 필요 없는 partition을 제외하는 최적화입니다. 날짜 range partition에서 occurred_at 조건이 명확하면 해당 월 partition만 읽을 수 있습니다.
EXPLAIN
SELECT *
FROM events
WHERE occurred_at >= '2026-05-01'
AND occurred_at < '2026-06-01';쿼리 조건이 partition key와 맞지 않으면 pruning이 제대로 되지 않아 모든 partition을 훑을 수 있습니다. partition을 나누는 기준은 실제 WHERE 조건과 맞아야 합니다.
운영 기준
| 상황 | 판단 |
|---|---|
| 월별로 오래된 데이터 삭제 | range partition 적합 |
| tenant별 데이터 격리와 관리 | list partition 검토 |
| 특정 키 기준 균등 분산 | hash partition 검토 |
| 테이블이 작거나 쿼리가 단순 | 일반 테이블 유지 |
| partition key 없이 자주 조회 | partition 효과 제한 |
partition은 성능 기능이면서 운영 기능입니다. 모든 쿼리를 빠르게 만드는 마법이 아니라, 큰 테이블을 관리 가능한 조각으로 나누는 설계입니다.
새 partition은 사전 검증 후 attach하고 default partition도 함께 확인한다
기존 table을 attach하면 PostgreSQL은 경계에 맞는지 확인하기 위해 attach 대상 table을 scan할 수 있습니다. 같은 범위의 CHECK 제약을 미리 검증해 두면 이 scan을 피할 수 있습니다. default partition이 있으면 새 범위에 들어갈 행이 없는지도 검사하므로, default partition에 새 범위를 제외하는 CHECK를 미리 두지 않으면 그 partition도 오래 잠길 수 있습니다.
CREATE TABLE events_2026_06
(LIKE events INCLUDING DEFAULTS INCLUDING CONSTRAINTS);
ALTER TABLE events_2026_06
ADD CONSTRAINT events_2026_06_range
CHECK (
occurred_at >= TIMESTAMPTZ '2026-06-01 00:00:00+00'
AND occurred_at < TIMESTAMPTZ '2026-07-01 00:00:00+00'
);
ALTER TABLE events
ATTACH PARTITION events_2026_06
FOR VALUES FROM (TIMESTAMPTZ '2026-06-01 00:00:00+00')
TO (TIMESTAMPTZ '2026-07-01 00:00:00+00');주의할 점
partition 수가 지나치게 많으면 planning 비용과 운영 복잡도가 늘어납니다. 작은 partition을 과도하게 많이 만드는 설계는 오히려 느릴 수 있습니다.
partitioned table의 인덱스, 제약, foreign key, unique 조건은 일반 테이블과 제약이 다르게 느껴질 수 있습니다. 특히 unique 제약은 partition key 포함 여부를 먼저 확인해야 합니다.
참고 링크
1 sources