명령어/DB

[PostgreSQL] 파티셔닝 큰 테이블을 기간별로 쪼개 관리한다

jykim23 2026. 7. 23. 21:58
반응형

설치·접속: PostgreSQL 설치와 접속

부제: 로그·이벤트처럼 계속 쌓이는 테이블을 월 단위로 나눠, 넣을 땐 자동으로 알맞은 조각에 들어가고 조회할 땐 필요한 조각만 스캔하고 싶을 때

-- 부모는 껍데기. 실제 데이터는 날짜 범위별 자식 테이블에 저장된다
CREATE TABLE m10_events (
  id bigint GENERATED ALWAYS AS IDENTITY,
  occurred_at date NOT NULL,
  payload text
) PARTITION BY RANGE (occurred_at);

CREATE TABLE m10_events_2026_01 PARTITION OF m10_events
  FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
CREATE TABLE m10_events_2026_02 PARTITION OF m10_events
  FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');
CREATE TABLE m10_events_2026_03 PARTITION OF m10_events
  FOR VALUES FROM ('2026-03-01') TO ('2026-04-01');

-- 부모에 넣으면 occurred_at을 보고 알맞은 자식으로 자동 라우팅
INSERT INTO m10_events (occurred_at, payload)
SELECT d, 'evt' FROM generate_series('2026-01-05'::date, '2026-03-25'::date, '5 days') d;

SELECT tableoid::regclass AS partition, count(*)
FROM m10_events GROUP BY 1 ORDER BY 1;
     partition      | count 
--------------------+-------
 m10_events_2026_01 |     6
 m10_events_2026_02 |     5
 m10_events_2026_03 |     5
(3 rows)

파티셔닝은 하나의 논리 테이블을 여러 물리 테이블(파티션)로 쪼갠다. INSERT는 파티션 키(occurred_at)를 보고 자동으로 맞는 조각에 넣어 주므로, 애플리케이션 코드는 부모 테이블만 바라보면 된다. 진짜 이득은 조회할 때 나온다. WHERE occurred_at에 범위 조건을 걸면 옵티마이저가 관계없는 파티션을 아예 건너뛰는데(파티션 프루닝), 수억 행 테이블에서도 한 달치만 스캔한다. 오래된 데이터를 지울 때도 DELETE 대신 파티션을 통째로 DROP하면 순식간에 끝난다.

이렇게도 쓴다

특정 기간 조건을 걸면 그 파티션만 스캔한다(파티션 프루닝). (조합: EXPLAIN)

EXPLAIN (COSTS OFF)
SELECT count(*) FROM m10_events
WHERE occurred_at >= '2026-02-01' AND occurred_at < '2026-03-01';
--  ->  Seq Scan on m10_events_2026_02   (2026-02 파티션 하나만 탄다)

 

범위가 아니라 값 목록으로 쪼갠다(지역·상태 코드 등). (조합: PARTITION BY LIST)

CREATE TABLE m10_by_region (id int, region text) PARTITION BY LIST (region);
CREATE TABLE m10_reg_kr PARTITION OF m10_by_region FOR VALUES IN ('KR','JP');
CREATE TABLE m10_reg_us PARTITION OF m10_by_region FOR VALUES IN ('US');
CREATE TABLE m10_reg_etc PARTITION OF m10_by_region DEFAULT;  -- 나머지는 여기로

 

어느 파티션에도 안 맞는 값을 받아 주는 기본 파티션을 둔다. (조합: DEFAULT)

INSERT INTO m10_by_region VALUES (4,'FR');   -- KR/US 아닌 값 → m10_reg_etc

 

오래된 파티션을 통째로 버려 즉시 정리한다(DELETE보다 빠름). (조합: DROP/DETACH)

DROP TABLE m10_events_2026_01;                       -- 1월치 전부 제거
ALTER TABLE m10_events DETACH PARTITION m10_events_2026_02;  -- 떼어내 보관

 

부모에 인덱스를 걸면 모든 파티션에 자동 전파된다.

CREATE INDEX ON m10_events (occurred_at);   -- 자식마다 개별 인덱스 생성

 

기존 일반 테이블을 파티션으로 편입한다. (조합: ATTACH PARTITION)

ALTER TABLE m10_events ATTACH PARTITION m10_events_2026_04
  FOR VALUES FROM ('2026-04-01') TO ('2026-05-01');
반응형