개요

DB에서 View는 가상의 테이블로, 접근이 허용된 자료만을 제한적으로 보여주기 위해 쿼리로 유도된 조회용 테이블이다.
데이터의 논리적 독립성을 제공할 수 있으며 관리 단순화, 데이터 보안의 이점이 있다.
저장공간에 물리적으로 구현되어있지는 않기때문에 기본적으로는 조회만 가능하다.
본래 뷰에서는 뷰를 구성하는 테이블들의 삽입, 삭제, 수정 등의 작업이 불가능하지만 뷰에 원본 테이블들의 기본키를 포함해서 뷰를 구성하면 가능하다.

여기까지가 View의 기본적인 구성이고, 지금까지 내가 작업했던 환경들에서는 View의 이점까지만 사용하면 충분했었다.
하지만 트래픽 처리 및 속도를 끌어올리기 위해서 물리 View인 Materialized View를 사용하는 기술 선택도 고려 가능하다는 관점이 있다는 것을 알게되었는데, View와 Materialized View의 차이점을 간단히 비교해 보고 필요하면 고려하고 적용해 보고 싶어서 포스팅을 하게 되었다.

Materialized View란?

Materialized View(물리화 뷰)는 일반 View처럼 쿼리로 정의되지만, 그 결과를 실제 테이블 형태로 물리적으로 저장해 두는 구조이다.
즉, View가 매 조회마다 원본 테이블을 참조해 데이터를 가져오는 반면, Materialized View는 쿼리 결과를 캐싱해 두고 이를 바로 읽기 때문에 조회 속도가 훨씬 빠르다.

단점으로는 원본 데이터가 변경되더라도 Materialized View가 자동으로 갱신되지 않는다는 점이다.
이를 보완하기 위해 REFRESH 명령어를 통해 수동 또는 자동(주기적)으로 갱신할 수 있다.
따라서 실시간성이 중요한 트랜잭션 처리보다는, 통계, 요약, 리포팅, 분석과 같은 대용량 읽기 중심의 환경에서 주로 사용된다.

Materialized View 제공 DBMS

DBMS지원 여부비고
OracleOCREATE MATERIALIZED VIEW 문법 기본 제공
PostgreSQLO9.3 이상부터 지원 (REFRESH MATERIALIZED VIEW)
SQL Server직접 지원하지 않음 (대신 Indexed View로 유사 기능 구현 가능)
MySQLX직접 지원하지 않음 (대신 트리거 + 테이블 조합으로 구현 가능)

View vs Materialized View 비교 관점

개념적 비교

구분ViewMaterialized View
저장 형태가상 테이블
(데이터 저장 안 함)
실제 데이터 저장
(물리 테이블 형태)
데이터 최신성항상 최신
(실시간 반영)
갱신 시점 기준으로 유지
(지연 가능)
조회 속도느림 (매번 원본 테이블 접근)빠름 (저장된 결과 조회)
갱신 필요 여부필요 없음REFRESH 필요
저장공간별도 공간 사용 안 함결과 저장을 위한 추가 공간 필요
적용 목적접근 제어, 논리적 독립성성능 향상, 대용량 통계/리포트
변경 가능성대부분 읽기 전용읽기 전용, 단 일부 DB에서는 직접 수정 가능
일관성 관리원본 테이블과 항상 일치최신 데이터와 다를 수 있음
(갱신 주기 의존)

비교표 요약

항목ViewMaterialized View
실시간성즉시 반영지연 반영
성능느림빠름
저장공간없음있음
갱신 주기불필요필요 (REFRESH)
활용 분야단순 조회, 보안 뷰통계, 리포트, 캐시, BI

생성 문법 비교

View 생성

CREATE VIEW view_name AS
SELECT column1, column2
FROM table_name
WHERE 조건;

Materialized View 생성

-- Oracle / PostgreSQL
CREATE MATERIALIZED VIEW mv_name AS
SELECT column1, column2
FROM table_name
WHERE 조건;

Materialized View 업데이트 문법

Materialized View 업데이트(Complete Refresh)

전체 데이터를 다시 생성 (정확하지만 느림)

REFRESH MATERIALIZED VIEW mv_name;

Materialized View 부분 업데이트

변경된 부분만 반영 (빠르지만 조건 제한 존재)

-- Oracle
BEGIN
  DBMS_MVIEW.REFRESH('mv_name', 'F');
END;