ClickHouse Upsert 메커니즘의 발전 과정

ClickHouse Upsert 메커니즘의 발전 과정

ClickHouse 분류
Core Architecture
Type
Research
작성자

Ken

ClickHouse는 대용량 분석(OLAP) 환경에 최적화된 컬럼형 데이터베이스로, 전통적인 UPDATE/DELETE 연산을 바로 지원하지 않고, 다양한 엔진과 내부 Mutation 메커니즘을 통해 Upsert(삽입 또는 수정) 기능을 진화시켜 왔습니다. 본 문서에서는 ClickHouse Upsert 메커니즘의 발전 과정을 연대기적으로 정리하고, 각 방식의 내부 원리, 장단점, 그리고 실전에서의 선택 기준을 ClickHouse 공식 문서 및 최신 릴리스 정보를 바탕으로 상세히 설명합니다.

1. ReplacingMergeTree: 중복행 대체 기반 Upsert (초기 ~ 2016)

원리 및 동작 방식

ReplacingMergeTree 엔진은 동일한 키(ORDER BY 기준)를 가진 중복 행 중 하나만 남기고 나머지를 제거하는 방식으로 Upsert 효과를 냅니다. 사용자는 여러 번 INSERT를 통해 같은 키의 데이터를 삽입할 수 있으며, 백그라운드에서 파티션 병합(merge)이 일어날 때 가장 마지막에 삽입된 행(혹은 지정된 버전 컬럼의 최대값 행)만 남깁니다. 병합 시점은 비동기적으로 결정되며, 필요 시 OPTIMIZE ... FINAL 명령으로 강제 병합도 가능합니다[1][2][3].

CREATE TABLE example
(
    id UInt64,
    value String,
    version UInt32
) ENGINE = ReplacingMergeTree(version)
ORDER BY id;

장단점

  • 장점: INSERT만으로 실질적인 UPDATE 효과를 얻을 수 있고, 쓰기 성능이 매우 뛰어남.
  • 단점: 병합 이전까지는 중복 데이터가 남아있어 SELECT 시 FINAL을 사용해야 일관된 최신 데이터를 조회할 수 있음. 병합 시점이 불확실하여 실시간 일관성 요구에는 부적합[1][3][4].

2. CollapsingMergeTree & VersionedCollapsingMergeTree: 1/-1 플래그 및 버전 기반 상태 갱신 (2016~2018)

CollapsingMergeTree

CollapsingMergeTree는 Sign(Int8) 컬럼을 사용하여, 동일 키에 대해 Sign=1(상태)과 Sign=-1(취소) 행이 쌍을 이루면 병합 시 두 행을 모두 제거(collapse)합니다. 이 방식은 이벤트 소싱이나 논리적 삭제/업데이트에 적합하며, INSERT만으로 상태 변경 이력을 관리할 수 있습니다[5][6].

CREATE TABLE collapsing_example
(
    id UInt64,
    value String,
    Sign Int8
) ENGINE = CollapsingMergeTree(Sign)
ORDER BY id;
  • 단점: 입력 순서에 민감하여 +1과 -1이 순차적으로 들어와야 정상 동작. 순서가 어긋나거나 누락되면 데이터 불일치 발생[6].

VersionedCollapsingMergeTree

2018년 v18.14에서 도입된 VersionedCollapsingMergeTree는 Sign과 Version 컬럼을 함께 사용해, 입력 순서와 무관하게 버전별로 쌍을 맞춰 안전하게 collapse합니다. 다중 쓰레드 환경, 비동기 파이프라인 등에서도 데이터 정합성을 보장합니다[4].

CREATE TABLE versioned_collapsing_example
(
    id UInt64,
    value String,
    Sign Int8,
    version UInt32
) ENGINE = VersionedCollapsingMergeTree(Sign, version)
ORDER BY (id, version);
  • 특징: Collapsing 대비 입력 순서 제약이 없고, 버전별로 안전하게 상태 갱신 가능. 단, +1/-1 행 관리를 애플리케이션에서 직접 해야 하며, SELECT 시 FINAL 필요[4].

3. Mutation 기반 ALTER UPDATE/DELETE: 직접 컬럼 수정 (2018~)

2018년 v18.12부터 ClickHouse는 MergeTree 계열 테이블에서 ALTER TABLE ... UPDATE/DELETE 문법을 지원하기 시작했습니다. 이 기능은 Mutation(데이터 변형)으로 구현되며, 조건에 맞는 행을 찾아 컬럼 값을 수정하거나 삭제 표시합니다. 실제로는 기존 데이터 파트를 읽어 새 파트를 생성하는 방식이며, 비동기로 처리됩니다[7].

ALTER TABLE example UPDATE value = 'new_value' WHERE id = 1;
ALTER TABLE example DELETE WHERE id = 2;
  • 장점: 표준 SQL UPDATE/DELETE 문법 사용, 병합 없이도 최신 데이터 즉시 조회 가능.
  • 단점: 컬럼 스토어 특성상 영향을 받는 열 파일 전체를 다시 써야 하므로, 데이터량이 많을수록 성능 부담이 큼. 작은 단위의 잦은 업데이트에는 비효율적임[7].

4. Lightweight Delete / Update: 경량 삭제 및 실시간 반영 (2022~2023)

Lightweight Delete

2022년 v22.8에서 도입된 Lightweight Delete는 DELETE FROM ... 구문을 통해 해당 조건의 행을 즉시 논리적으로 숨깁니다. 실제로는 _row_exists 컬럼에 마스크를 기록하고, 물리 삭제는 차후 병합(merge) 시에만 일어납니다[8].

DELETE FROM example WHERE id = 1;
  • 특징: DELETE 실행 직후부터 해당 행이 조회 결과에 나타나지 않음. 물리적 삭제는 지연되므로, 대량 삭제 시 SELECT 성능에 일시적 영향 가능[8].

Lightweight Update (On-the-fly Mutation)

2023년경 실험적으로 도입된 on-the-fly mutation 기능은 UPDATE 결과를 즉시 SELECT에 반영합니다. UPDATE 명령 실행 후 Mutation이 백그라운드에서 완료되기 전이라도, SELECT 시 변경된 값을 즉시 보여줍니다. 실제 디스크 반영은 기존 Mutation과 동일하게 나중에 처리됩니다.

  • 장점: UPDATE 후 즉시 일치하는 값 조회 가능.
  • 제한: 서브쿼리, 비결정적 함수 등 일부 UPDATE에는 제한이 있고, SELECT 성능 저하 가능성[8].

5. 패치 파트(Patch Parts) 기반 UPDATE: 컬럼형 DB에 최적화된 고속 업데이트 (2025~)

2025년 v25.7 릴리스에서 패치 파트(patch part) 기반 UPDATE가 도입되어, 표준 SQL UPDATE 문법으로 실시간 경량 업데이트가 가능해졌습니다. UPDATE 실행 시, 변경 대상 열의 새로운 값만 별도 패치 파트에 저장하고, SELECT 시 즉시 반영됩니다. 이후 백그라운드 병합 시 원본 파트와 패치 파트가 합쳐지며, 최종적으로 데이터가 일관되게 정리됩니다[9][attachment,ClickHouse Upsert 기능의 연대기 및 엔진별 메커니즘.pdf].

  • 장점: 변경된 컬럼만 기록하므로 I/O 부담이 적고, UPDATE 결과를 바로 조회 가능. 작은 단위의 잦은 업데이트에도 효율적.
  • 단점: 패치 파트가 많아지면 SELECT 성능 저하 및 파트 수 증가 가능. 전체 데이터의 10% 이하 부분 업데이트에 적합하며, 대규모 수정은 기존 Mutation 권장.

6. Upsert 방식별 비교 및 선택 가이드

비교 요약

엔진/기능
주요 특징
장점
단점
ReplacingMergeTree
병합 시 동일 키 중 마지막 행만 유지
INSERT만으로 업데이트 효과, 고속 쓰기
병합 전까지 중복 데이터 잔존, 즉각 일관성 부족(FINAL 필요)
CollapsingMergeTree
Sign(+1/-1) 쌍 병합 시 상쇄
INSERT로 삭제/업데이트 표현, 저장공간 절약
입력 순서 요구, 불완전 쌍 처리 어려움
VersionedCollapsingMergeTree
Sign+Version, 버전별 쌍 병합
순서 무관 안전 갱신
+1/-1 이중 INSERT 필요, SELECT 시 FINAL 필요
ALTER Mutation
조건부 컬럼 수정/삭제
표준 SQL 사용, 최신값 즉시 조회
전체 컬럼 재기록, 대량/빈번 업데이트 시 부하
Lightweight Delete
_row_exists 마스크로 즉시 숨김
빠른 삭제, 대부분 컬럼 재기록 불필요
merge 전까지 공간 차지, SELECT 성능 영향 가능
On-the-fly Update
즉시 SELECT 반영
UPDATE 후 지연 없는 일관성
백그라운드 I/O는 여전, 복잡한 UPDATE 제한
Patch Parts UPDATE
패치 파트에 변경분만 기록
컬럼 단위 고속 업데이트, SQL UPDATE 지원
패치 많으면 SELECT/파트 수 영향, 대량 수정 부적합

선택 기준 및 실전 가이드

  • 실시간 일관성, 표준 SQL UPDATE 필요: 패치 파트 기반 UPDATE, on-the-fly mutation 활용.
  • 대량 데이터, 변경 빈도 낮음: ReplacingMergeTree, CollapsingMergeTree 등 삽입 기반 엔진 활용.
  • 상태 이력 관리, 이벤트 소싱: Collapsing/VersionedCollapsing 계열 추천.
  • 자주 부분 업데이트, 빠른 반영: Patch parts UPDATE.
  • 대규모 일괄 수정/삭제: 기존 ALTER UPDATE/DELETE(Mutation) 활용.

최신 패치 파트 기반 UPDATE의 도입으로 ClickHouse는 OLAP DB임에도 실시간 Upsert에 가까운 경험을 제공하며, 사용자는 워크로드 특성에 맞는 엔진 및 메커니즘을 선택해 최적의 성능과 편의성을 얻을 수 있습니다[attachment,ClickHouse Upsert 기능의 연대기 및 엔진별 메커니즘.pdf][1][5][9][10].

참고 문서 및 공식 자료

  • ReplacingMergeTree | ClickHouse Docs
  • CollapsingMergeTree | ClickHouse Docs
  • VersionedCollapsingMergeTree | ClickHouse Docs
  • ALTER TABLE ... UPDATE Statements | ClickHouse Docs
  • Lightweight Delete | ClickHouse Docs
  • 2025 Changelog | ClickHouse Docs
  • How to Upsert Rows into ClickHouse

ClickHouse Upsert 메커니즘은 계속해서 진화 중이며, 최신 릴리스 및 공식 문서를 참고해 워크로드에 맞는 최적의 방식을 선택하는 것이 중요합니다.