PostgreSQL Materialized View 사용과 갱신 전략
PostgreSQL의 materialized view 사용법과 갱신 전략을 초보자도 이해하기 쉽게 정리한 기술 자료
목차
개요
Materialized view(이하 MV)는 복잡한 쿼리 결과를 디스크에 저장해 조회 성능을 높이는 도구다. 일반 뷰와 달리 결과를 캐시하므로 읽기 작업이 많은 서비스에서 자주 사용된다. 다만 저장된 결과와 원본 테이블의 불일치를 관리하는 갱신 전략이 핵심이다.
MV의 기본 개념
정의와 특징
MV는 쿼리 결과를 물리적으로 저장한다. 따라서 조회 시 복잡한 조인이나 집계를 매번 수행할 필요가 없고 응답 속도가 빨라진다. 반면, 원본 데이터가 변경되면 MV를 갱신해야 최신 상태를 유지할 수 있다.
장단점 요약
- 장점: 읽기 성능 향상, 리소스 절약, 복잡한 집계의 사전 계산
- 단점: 갱신 비용 발생, 저장 공간 소모, 실시간성 저하 가능성
MV 생성과 조회 예시
기본적인 MV 생성과 조회 방법은 간단하다. 아래 예시는 주문 테이블에서 일별 매출 합계를 미리 계산하는 MV다.
CREATE MATERIALIZED VIEW daily_sales AS
SELECT date_trunc('day', created_at) AS day,
sum(amount) AS total
FROM orders
GROUP BY day;
-- 조회
SELECT * FROM daily_sales WHERE day >= '2024-01-01';
갱신 전략
갱신 전략은 시스템 요구사항(데이터 신선도, 성능, 예산)에 따라 달라진다. 주요 전략은 다음과 같다.
1. 주기적 전체 갱신
가장 단순한 방법은 일정 주기(예: 매시간, 매일)로 REFRESH MATERIALIZED VIEW를 실행하는 것이다. 구현이 쉽고 상태 관리가 간단하지만 갱신 시 전체 데이터를 다시 계산하므로 비용이 크다.
REFRESH MATERIALIZED VIEW daily_sales;
-- 또는 동시성 허용(유일 인덱스 필요)
REFRESH MATERIALIZED VIEW CONCURRENTLY daily_sales;
2. CONCURRENTLY 옵션 활용
REFRESH MATERIALIZED VIEW CONCURRENTLY는 조회 중에도 갱신이 가능해 가용성을 높인다. 단, MV에 유일한 인덱스가 있어야 하며 갱신 시간이 길어질 수 있다. 트래픽이 많은 환경에서 권장된다.
3. 증분(부분) 갱신 패턴
PostgreSQL 자체는 자동 증분 갱신을 제공하지 않는다. 대신 증분 갱신을 흉내 내는 방법으로 임시 테이블에 변경분(delta)을 수집하고 MV를 병합하거나, 트리거로 변경분을 다른 테이블에 기록한 뒤 이를 반영하는 방식이 있다. 이 방식은 갱신 비용을 크게 줄일 수 있다.
-- 변경 감지를 위한 로그 테이블
CREATE TABLE orders_delta (id bigint PRIMARY KEY, updated_at timestamptz);
-- 주기 작업 예시(간단 병합)
WITH d AS (
SELECT date_trunc('day', o.created_at) AS day, sum(o.amount) AS s
FROM orders o
WHERE o.updated_at > now() - interval '1 hour'
GROUP BY day
)
-- 임시 테이블에 합친 뒤 MV를 업데이트하는 방식 적용
4. 실시간과 근실시간 설계
실시간 요구가 강하면 MV 대신 스트리밍(예: logical replication, Kafka)이나 인메모리 캐시를 고려한다. 근실시간이라면 짧은 주기로 CONCURRENTLY 갱신하거나 증분 병합을 조합해 만족시킬 수 있다.
운영 팁과 성능 고려사항
- 유일 인덱스: CONCURRENTLY 갱신 시 유일 인덱스가 필요하다. 설계 시 고려한다.
- 인덱스 생성: MV에도 적절한 인덱스를 생성해 조회 성능을 유지한다.
- 동시성 영향: 대용량 MV를 자주 전체 갱신하면 I/O와 잠금 비용이 커진다.
- 모니터링: 갱신 시간, 디스크 사용량, 조회 빈도 등을 모니터링한다.
실무 적용 예
예를 들어 일별 매출을 거의 실시간으로 제공해야 하면서 전체 테이블 스캔 비용을 줄이고 싶다면 다음 조합을 권장한다.
- 기본 MV에 일별 집계 저장
- 최근 몇 시간 데이터는 실시간 집계를 별도 테이블에 유지
- 정기적으로 두 테이블을 병합해 MV를 보완
- 가능하면 REFRESH CONCURRENTLY를 사용해 서비스 영향 최소화
정리
Materialized view는 읽기 성능 개선에 유용하지만 갱신 비용과 데이터 신선도 사이에서 균형을 잡아야 한다. 주기적 전체 갱신, CONCURRENTLY 갱신, 증분 병합 등 다양한 전략을 요구사항에 맞춰 조합하면 실무에서 효과적으로 활용할 수 있다.