ClickHouse MV vs RMV
🏎️

ClickHouse MV vs RMV

ClickHouse 분류
Core Architecture
Type
Lab
작성자

Ken

고빈도 INSERT 환경에서 Part 수를 80% 줄이고 리소스 효율성을 극대화하는 방법에 대한 연구입니다. 30분간 190만 건의 이벤트 데이터를 삽입하며 Materialized View(MV)와 Refreshable Materialized View(RMV)의 리소스 효율성을 비교 테스트했습니다. 결과적으로 RMV는 MV 대비 Part 수를 3배 줄이고, 배치 처리를 통해 Merge 부하를 현저히 감소시켰습니다. 5분 이상의 데이터 지연이 허용되는 분석 워크로드에서는 RMV가 확실한 선택입니다.

  • 들어가며: 왜 이 비교가 중요한가?
  • 테스트 환경 및 설계
  • 테스트 목표
  • 아키텍처
  • 스키마 설계
  • 테스트 결과 분석
  • 1. 데이터 볼륨
  • 2. Part 생성 비교 - 핵심 발견
  • 3. 처리 패턴 시각화
  • 왜 이런 차이가 발생하는가?
  • ClickHouse의 Part 메커니즘 이해
  • 배치 처리의 효율성
  • 실무 적용 가이드
  • RMV를 선택해야 하는 경우
  • MV를 선택해야 하는 경우
  • 선택 가이드 플로우차트
  • 성능 최적화 팁
  • RMV Refresh 주기 결정
  • RMV APPEND 모드에서의 중복 방지
  • 모니터링
  • 결론
  • 참고 자료

들어가며: 왜 이 비교가 중요한가?

ClickHouse를 운영하다 보면 반드시 마주치는 질문이 있습니다.

"실시간 집계가 꼭 필요한가? 아니면 몇 분 정도 지연되어도 괜찮은가?"

이 질문에 대한 답이 Materialized View(MV)를 쓸지, Refreshable Materialized View(RMV)를 쓸지를 결정합니다. 하지만 단순히 "지연 시간"만의 문제가 아닙니다. 고빈도 INSERT 환경에서 두 방식의 리소스 사용 패턴은 완전히 다르며, 이는 인프라 비용과 시스템 안정성에 직접적인 영향을 미칩니다.

이 글에서는 실제 테스트 데이터를 기반으로 MV와 RMV의 내부 동작 차이를 분석하고, 어떤 상황에서 어떤 방식을 선택해야 하는지 명확한 가이드를 제시합니다.

테스트 환경 및 설계

테스트 목표

가설: 고빈도 INSERT 환경에서 RMV(5분 배치)가 MV(실시간)보다 리소스 효율성이 높을 것이다.

아키텍처

테스트는 ClickHouse Cloud(v25.10.1.6953) 환경에서 진행되었으며, 다음과 같은 구조로 설계했습니다.

스키마 설계

Source 테이블은 전형적인 이벤트 로그 구조로 설계했습니다.

CREATE TABLE mv_vs_rmv.events_source
(
    event_time DateTime64(3) DEFAULT now64(3),
    user_id UInt32,
    event_type LowCardinality(String),
    page_url String,
    session_id UUID,
    country LowCardinality(String),
    device_type LowCardinality(String),
    revenue Decimal(10,2),
    quantity UInt16
)
ENGINE = MergeTree()
PARTITION BY toYYYYMMDD(event_time)
ORDER BY (event_type, user_id, event_time);

MV와 RMV는 동일한 집계 로직을 수행합니다. 5분 단위로 이벤트를 그룹화하고, 이벤트 타입, 국가, 디바이스별로 카운트, 유니크 유저 수, 매출 합계를 계산합니다.

테스트 결과 분석

1. 데이터 볼륨

30분간의 테스트 결과, 다음과 같은 데이터가 생성되었습니다.

테이블
행 수
설명
events_source
1,908,000
원본 이벤트 데이터
events_agg_mv
1,200
MV 집계 결과
events_agg_rmv
1,800
RMV 집계 결과

흥미로운 점은 RMV가 MV보다 더 많은 집계 행을 생성했다는 것입니다. 이는 RMV가 더 완전한 시간대 커버리지를 제공했음을 의미합니다. MV는 실시간으로 작은 블록 단위로 처리하다 보니 일부 시간대의 데이터가 여러 Part에 분산되어 있을 수 있습니다.

2. Part 생성 비교 - 핵심 발견

이 테스트의 가장 중요한 발견은 Part 생성 패턴의 차이입니다.

메트릭
MV
RMV
비율
Total Parts
3
1
3.0x
Active Parts
3
1
3.0x
Total Disk Size
11.63 KiB
15.17 KiB
0.77x
Avg Part Size
3.88 KiB
15.17 KiB
0.26x

RMV는 단 1개의 Part만 생성한 반면, MV는 3개의 Part를 생성했습니다. 여기서 주목할 점은 MV의 Part 수가 생각보다 적다는 것입니다. 초기에는 77개까지 증가했다가 ClickHouse의 Background Merge가 활발하게 작동하면서 최종적으로 3개로 줄었습니다.

MV Part 수 변화: 77 → 5 → 3 (Background Merge 작동)
RMV Part 수: 1 (처음부터 1개 유지)

이것이 핵심입니다. MV는 Part를 많이 생성하고 나중에 Merge하는 반면, RMV는 처음부터 큰 Part를 적게 생성합니다. Merge 과정 자체가 CPU와 I/O 리소스를 소비하므로, RMV의 접근 방식이 근본적으로 더 효율적입니다.

3. 처리 패턴 시각화

두 방식의 처리 패턴을 시간축으로 표현하면 다음과 같습니다.

MV 패턴: 물방울이 계속 떨어지는 것처럼 작은 Part들이 지속적으로 생성되고, 백그라운드에서 이를 합치느라 시스템이 계속 일을 합니다.

RMV 패턴: 5분마다 큰 물줄기가 쏟아지는 패턴입니다. 중간에는 완전히 유휴 상태이고, 5분마다 집중적으로 처리합니다.

왜 이런 차이가 발생하는가?

ClickHouse의 Part 메커니즘 이해

ClickHouse는 데이터를 Part 단위로 저장합니다. INSERT가 발생하면 새로운 Part가 생성되고, 백그라운드에서 작은 Part들을 큰 Part로 병합(Merge)합니다. 이 Merge 과정은 다음과 같은 비용을 수반합니다.

  1. CPU 사용: 데이터 정렬 및 병합 연산
  2. Disk I/O: 기존 Part 읽기 + 새 Part 쓰기
  3. Memory: Merge 과정에서의 버퍼링

MV는 INSERT마다 트리거되므로, 초당 1,000건의 INSERT가 발생하면 매우 빈번하게 Part가 생성됩니다. ClickHouse는 이를 감당하기 위해 지속적으로 Merge를 수행해야 합니다.

배치 처리의 효율성

RMV의 5분 배치 처리가 효율적인 이유는 다음과 같습니다.

1. I/O 효율성

30분간 처리할 데이터양은 동일하지만, 처리 방식이 다릅니다.

MV:  1,800번의 작은 INSERT 처리 → 1,800번의 Part 생성 시도
RMV: 6번의 큰 배치 처리 → 6번의 Part 생성

디스크 I/O는 작은 쓰기를 많이 하는 것보다 큰 쓰기를 적게 하는 것이 훨씬 효율적입니다. 이는 SSD의 쓰기 증폭(Write Amplification) 문제와도 연관됩니다.

2. Aggregation 효율성

MV는 INSERT 단위로 집계하므로, 같은 시간대(5분 버킷)의 데이터가 여러 Part에 분산될 수 있습니다. 최종 조회 시 이 Part들을 모두 읽어서 합쳐야 합니다.

RMV는 5분치 데이터를 한 번에 처리하므로, 시간대별로 완전한 집계가 이루어집니다. 조회 시 추가적인 병합 연산이 필요 없습니다.

3. 리소스 사용 패턴

범례: Bar = MV (일정한 ~30%), Line = RMV (5분마다 80% 스파이크, 그 외 ~5%)

RMV의 패턴은 클라우드 환경에서 특히 유리합니다. 스파이크 외의 시간에 다른 워크로드가 리소스를 사용할 수 있기 때문입니다.

실무 적용 가이드

RMV를 선택해야 하는 경우

1. 고빈도 INSERT 환경

초당 수백~수천 건 이상의 INSERT가 발생하는 환경에서는 RMV가 확실한 선택입니다. IoT 센서 데이터, 웹 이벤트 트래킹, 로그 수집 등이 대표적인 예입니다.

2. BI/리포팅 워크로드

대시보드가 5분 정도의 지연을 허용한다면, RMV로 백엔드 부하를 크게 줄일 수 있습니다.

3. 복잡한 집계 로직

uniqExact(), groupArray(), 여러 테이블 JOIN 등 무거운 연산이 포함된 집계는 배치로 처리하는 것이 효율적입니다.

4. 비용 최적화가 중요한 경우

ClickHouse Cloud의 경우 컴퓨팅 리소스에 따라 비용이 책정됩니다. RMV의 간헐적 사용 패턴은 전체 비용을 줄이는 데 도움이 됩니다.

MV를 선택해야 하는 경우

1. 실시간 요구사항

1초 미만의 데이터 지연이 필수인 경우에는 MV를 사용해야 합니다. 실시간 알림, 이상 탐지, 라이브 대시보드 등이 해당됩니다.

2. 저빈도 INSERT

분당 수백 건 이하의 INSERT 환경에서는 MV의 오버헤드가 크지 않습니다.

3. 간단한 집계

count(), sum() 정도의 가벼운 집계는 실시간 처리해도 부담이 적습니다.

선택 가이드 플로우차트

성능 최적화 팁

RMV Refresh 주기 결정

Refresh 주기는 데이터 지연 허용 범위와 배치 크기의 균형점에서 결정해야 합니다.

Refresh 주기
장점
단점
1분
낮은 지연
배치 효율성 감소
5분
균형잡힌 선택
-
10분
높은 배치 효율성
지연 증가
1시간
매우 효율적
긴 지연

대부분의 분석 워크로드에서는 5분이 좋은 시작점입니다.

RMV APPEND 모드에서의 중복 방지

APPEND 모드의 RMV는 데이터를 덮어쓰지 않고 추가합니다. 중복을 방지하려면 WHERE 절의 시간 범위를 신중하게 설계해야 합니다.

-- 안전한 시간 범위 설정
WHERE event_time >= now() - INTERVAL 6 MINUTE  -- 5분 + 1분 버퍼
  AND event_time < now() - INTERVAL 1 MINUTE   -- 최신 데이터 제외

또는 ReplacingMergeTree를 사용하여 중복을 자동 처리할 수 있습니다.

모니터링

RMV의 상태를 모니터링하려면 system.view_refreshes 테이블을 활용합니다.

SELECT
    database,
    view,
    status,
    last_success_time,
    next_refresh_time,
    last_refresh_result
FROM system.view_refreshes
WHERE database = 'your_database';

결론

이번 테스트를 통해 다음을 정량적으로 확인했습니다.

  1. RMV는 Part 수를 3배 줄입니다 (3 → 1)
  2. RMV는 처음부터 큰 Part를 생성하여 Merge 필요성 자체를 줄입니다
  3. RMV는 더 완전한 데이터 커버리지를 제공합니다 (1,800 vs 1,200 rows)

고빈도 INSERT 환경에서 5분 이상의 데이터 지연이 허용된다면, RMV는 단순한 대안이 아닌 확실한 선택입니다. Part 관리 효율성 향상은 곧 Merge 부하 감소, CPU/Memory 절약, 그리고 궁극적으로 인프라 비용 절감으로 이어집니다.

물론 실시간성이 필수인 경우에는 여전히 MV가 필요합니다. 중요한 것은 요구사항을 정확히 파악하고, 적절한 도구를 선택하는 것입니다.

참고 자료

  • ClickHouse Materialized Views Documentation
  • ClickHouse Refreshable Materialized Views

활용 코드

clickhouse-hols/workload/mv-vs-rmv at main · litkhai/clickhouse-hols

ClickHouse Hands-on Labs . Contribute to litkhai/clickhouse-hols development by creating an account on GitHub.

clickhouse-hols/workload/mv-vs-rmv at main · litkhai/clickhouse-hols

이 글은 ClickHouse Cloud v25.10.1.6953 환경에서의 테스트 결과를 기반으로 작성되었습니다.