반응형
설치·접속: PostgreSQL 설치와 접속
부제: 대시보드가 계속 읽는 집계 뷰를 새로 굽고 싶은데, 일반 REFRESH는 갱신 내내 조회를 통째로 막아 버려서 서비스 중단 없이 최신화하고 싶을 때
-- 전제조건: 행을 유일하게 식별하는 UNIQUE 인덱스가 반드시 있어야 한다
CREATE UNIQUE INDEX m10_mv_pk ON m10_mv(id);
-- [세션 A] 대용량 뷰를 CONCURRENTLY로 갱신 (약 1.9초 소요)
REFRESH MATERIALIZED VIEW CONCURRENTLY m10_big; -- Time: 1889.277 ms
-- [세션 B] 세션 A가 한창 갱신하는 중에 조회 → 차단되지 않고 즉답
SELECT grp, c FROM m10_big ORDER BY grp LIMIT 3; -- Time: 5.795 ms
grp | c
-----+------
0 | 3000 <- 갱신 진행 중엔 아직 '예전' 결과가 보인다
1 | 3000
2 | 3000
(3 rows) -- 갱신 완료 후 다시 조회하면 c = 30000일반 REFRESH MATERIALIZED VIEW는 뷰에 AccessExclusiveLock을 걸어, 다시 굽는 동안 모든 SELECT를 대기시킨다. 뷰가 크면 그 시간 내내 대시보드가 멈춘다. CONCURRENTLY를 붙이면 갱신은 새 데이터를 임시로 만든 뒤 변경분만 반영하는 방식이라, 조회를 막는 강한 잠금을 잡지 않는다. 위에서 세션 A가 1.9초간 갱신하는 동안 세션 B의 조회는 5.8ms 만에 예전 스냅샷을 반환했고, 갱신이 끝난 뒤에야 새 값(30000)이 보였다. 읽는 쪽은 한순간도 끊기지 않는다. 대신 각 행을 유일하게 식별하는 UNIQUE 인덱스가 없으면 이 방식을 쓸 수 없다.
이렇게도 쓴다
UNIQUE 인덱스가 없으면 CONCURRENTLY는 거부된다(반드시 먼저 만든다).
REFRESH MATERIALIZED VIEW CONCURRENTLY m10_mv;
-- ERROR: cannot refresh materialized view "public.m10_mv" concurrently
-- HINT: Create a unique index with no WHERE clause ...
읽기가 잠깐 멈춰도 되는 소규모 뷰는 그냥 일반 갱신이 더 빠르다.
REFRESH MATERIALIZED VIEW m10_mv; -- 짧게 잠그고 통째로 다시 굽기
크론으로 주기 갱신을 자동화한다. (조합: 셸 + psql)
# 매시 정각, 조회 안 끊고 새로고침
0 * * * * psql -d shop -c "REFRESH MATERIALIZED VIEW CONCURRENTLY m10_big"
정의만 먼저 만들고 데이터는 첫 REFRESH 때 채운다. (조합: WITH NO DATA)
CREATE MATERIALIZED VIEW m10_mv2 AS SELECT ... WITH NO DATA;
REFRESH MATERIALIZED VIEW m10_mv2; -- 이때 처음 채워짐
채워졌는지 시스템 카탈로그로 확인한다. (조합: pg_matviews)
SELECT matviewname, ispopulated FROM pg_matviews WHERE matviewname = 'm10_big';
조회 성능을 위해 뷰 위에 추가 인덱스를 건다.
CREATE INDEX ON m10_big(c DESC); -- CONCURRENTLY 갱신은 인덱스를 자동 반영반응형
'명령어 > DB' 카테고리의 다른 글
| [PostgreSQL] 파티셔닝 큰 테이블을 기간별로 쪼개 관리한다 (0) | 2026.07.23 |
|---|---|
| [PostgreSQL] 부분 인덱스(partial index)로 소수 행만 인덱싱한다 (0) | 2026.07.23 |
| [PostgreSQL] 머티리얼라이즈드 뷰 무거운 집계를 미리 구워 대시보드에서 즉답한다 (0) | 2026.07.23 |
| [PostgreSQL] 긴 트랜잭션 열어둔 채 방치하면 VACUUM이 죽은 튜플을 못 지운다 (0) | 2026.07.23 |
| [PostgreSQL] LISTEN/NOTIFY 폴링 없이 DB 이벤트를 실시간으로 받는다 (0) | 2026.07.23 |