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