본문으로 건너뛰기
7.4 파티션 가지치기

7.4 파티션 가지치기

파티셔닝의 효과는 partition pruning으로 결정됩니다. 쿼리의 WHERE 절을 보고 건드릴 필요 없는 파티션을 제외하는 메커니즘입니다. pruning이 잘 되면 한 파티션만 스캔, 안 되면 모든 파티션을 스캔 — 결과는 같지만 비용은 100배 이상 차이날 수 있습니다.

두 단계

PostgreSQL은 두 시점에 pruning을 시도합니다.

단계시점조건
plan-time pruning옵티마이저가 plan 만들 때WHERE에 상수 또는 안전한 식
execution-time pruning실행 직전prepared statement의 파라미터·generic plan
-- plan-time: WHERE의 값이 상수 → 즉시 가지치기
EXPLAIN SELECT * FROM events WHERE created_at >= '2026-05-01';
-- 결과: events_2026_05만 스캔

-- execution-time: 파라미터가 prepare 시점에 모름
PREPARE q AS SELECT * FROM events WHERE created_at >= $1;
EXPLAIN EXECUTE q ('2026-05-01');
-- 결과: "Subplans Removed: N" 형태로 실행 시점에 가지치기

EXPLAIN에서 확인

 Append  (cost=...)
   Subplans Removed: 11             -- 12개 중 11개 가지치기
   ->  Seq Scan on events_2026_05  -- 남은 1개만 스캔

Subplans Removed가 보이면 execution-time pruning이 동작한 것.

plan-time이면 아예 다른 파티션 노드가 plan에 안 나타납니다.

동작하는 WHERE

pruning은 옵티마이저가 파티션 경계와 WHERE를 직접 비교 가능할 때만 동작합니다.

WHEREpruning
created_at = '2026-05-15'
created_at BETWEEN ... AND ...
created_at > now() - interval '1 day'✓ (stable 식)
country IN ('KR', 'JP') (LIST)
WHERE date_trunc('day', created_at) = '2026-05-15'잘 안 됨 (함수 결과)
WHERE created_at::date = '2026-05-15'잘 안 됨 (cast 함수)
WHERE created_at = (SELECT max(...) FROM ...)execution-time만

함수가 들어가면 옵티마이저가 결과를 미리 모르므로 모든 파티션을 스캔합니다. WHERE에 파티션 키가 그대로 들어가는 형태가 가장 안전.

동작 사례

range 파티션 + 상수

EXPLAIN SELECT * FROM events
 WHERE created_at >= '2026-05-01' AND created_at < '2026-06-01';

 Seq Scan on events_2026_05    -- 단일 파티션만

list 파티션 + IN

EXPLAIN SELECT * FROM orders WHERE country IN ('KR', 'JP');

 Append
   ->  Seq Scan on orders_kr
   ->  Seq Scan on orders_jp

hash 파티션 + 등호

EXPLAIN SELECT * FROM users WHERE id = 42;
 Seq Scan on users_p3    -- 해시 결과로 한 파티션만

JOIN에서의 pruning

JOIN 키가 파티션 키면 파티션-와이즈 조인이 가능 (PG 11+). 같은 파티션끼리만 join.

SET enable_partitionwise_join = on;     -- PG 11~13 기본 off
-- PG 14+: 기본 on
 Append
   ->  Hash Join
         ->  Seq Scan on a_2026_05
         ->  Hash on b_2026_05
   ->  Hash Join
         ->  Seq Scan on a_2026_06
         ->  Hash on b_2026_06

비슷하게 enable_partitionwise_aggregate = on은 파티션별 부분 집계 후 합치는 plan을 활성화합니다.

GROUP BY 가지치기

SET enable_partitionwise_aggregate = on;

SELECT user_id, count(*)
  FROM events
 WHERE created_at >= '2026-05-01' AND created_at < '2026-06-01'
 GROUP BY user_id;

-- 한 파티션 안에서 집계 → 결과 작음

함정 1 — now()·current_date

WHERE created_at > now() - interval '1 day'

now()는 STABLE 함수라 한 트랜잭션에서 고정. 옵티마이저가 plan-time에 값을 미리 모름 → execution-time pruning만 가능합니다.

실용적으로는 execution-time이면 충분히 빠릅니다. 하지만 EXPLAIN이 generic plan을 만들 때 모든 파티션이 plan에 들어있어 plan 시간이 길어질 수 있습니다.

대응: 애플리케이션에서 상수로 만들어 보냄.

since = datetime.now() - timedelta(days=1)
cur.execute("SELECT ... WHERE created_at > %s", (since,))
--  식은 prepared statement의 $1  execution-time pruning

함정 2 — 캐스팅·함수 호출

WHERE date_trunc('day', created_at) = '2026-05-15'  -- 모든 파티션 스캔
WHERE created_at::date = '2026-05-15'                -- 같음
WHERE EXTRACT(month FROM created_at) = 5             -- 모든 파티션 스캔

대응: 파티션 키를 그대로 둔 범위 비교로 재작성합니다.

WHERE created_at >= '2026-05-15' AND created_at < '2026-05-16'  -- 가지치기 OK

함정 3 — 파티션 너무 많음

100+ 파티션이 되면 plan time 자체가 길어집니다. 5ms 옵티마이징이 50ms로 자라는 식.

완화메모
활성 파티션 수 제한5년치 월 파티션이면 60개 — OK
오래된 파티션은 분기/년 단위로 합침 (rolling)pg_partman의 retention 정책
plan_cache_mode = force_generic_plan매번 plan 안 하고 caching

함정 4 — IN (subquery)

WHERE created_at IN (SELECT max(t) FROM ...)

서브쿼리 결과를 옵티마이저가 미리 모름 → 모든 파티션 스캔. 가능하면 상수 또는 변수로 분리합니다.

EXPLAIN 활용 패턴

운영 중 슬로우 쿼리를 진단할 때 pruning 동작 확인:

EXPLAIN (ANALYZE, BUFFERS)
SELECT ...
;

체크:

신호의미
Append 아래에 한 자식만plan-time pruning 성공
Subplans Removed: Nexecution-time pruning
모든 파티션이 자식으로 나열됨pruning 실패 — WHERE 식 재검토
Workers Planned: 0parallel partition scan이 안 됨 (작은 파티션)

정리

  • pruning은 plan-time과 execution-time 두 단계로 동작
  • WHERE에 파티션 키가 그대로 들어가야 안전 — 함수·cast 회피
  • now()·current_date는 execution-time만 — 보통 충분히 빠름
  • partition-wise join·aggregate는 PG 11+ 옵션. 14+ 기본 on
  • 파티션 100+ 개면 plan time 자체가 비용 — 활성 파티션 수 관리 중요
  • 진단은 EXPLAIN의 Subplans RemovedAppend의 자식 수

다음 절(7.5)에서는 파티션 생성·삭제·archive를 자동화하는 pg_partman을 봅니다.