업데이트 전략 선택
- 삽입을 통해 업데이트를 처리하는 특수 테이블 엔진 사용
UPDATE ... SET또는ALTER TABLE ... UPDATESQL 문과 같은 선언적 업데이트 사용
특수한 테이블 엔진을 사용해야 하는 경우
| Engine | Syntax | When to use |
|---|---|---|
| ReplacingMergeTree | ENGINE = ReplacingMergeTree | 대량의 데이터를 업데이트할 때 사용합니다. 이 테이블 엔진은 머지 중 데이터 중복 제거에 최적화되어 있습니다. |
| CoalescingMergeTree | ENGINE = CoalescingMergeTree | 데이터가 조각난 형태로 유입되고, 전체 행 교체가 아니라 컬럼 단위 coalescing이 필요한 경우 사용합니다. |
| CollapsingMergeTree | ENGINE = CollapsingMergeTree(Sign) | 개별 행이 자주 업데이트되거나, 시간에 따라 변하는 객체의 최신 상태를 유지해야 하는 시나리오에 사용합니다. 예를 들어 사용자 활동이나 게시물 통계를 추적할 때 유용합니다. |
FINAL 키워드를 사용해야 합니다.
다른 엔진 종류도 있지만, 여기 소개한 엔진이 가장 일반적으로 사용됩니다.
선언적 업데이트를 사용하는 경우
| 메서드 | 구문 | 사용 시점 |
|---|---|---|
| 경량 업데이트 | UPDATE [table] SET ... WHERE | 대부분의 시나리오에서는 이를 사용하십시오. 특히 애플리케이션이나 워크플로의 일부로 빈번하게 작은 규모의 UPDATE(테이블의 약 10% 이하)를 수행할 때 적합합니다. 예를 들어, 사용자가 자신의 이벤트 이력을 삭제하려고 하는데 이벤트가 많은 사용자가 공유하는 멀티테넌트 테이블 전반에 분산되어 있는 경우입니다. 이 방식은 전체 컬럼을 다시 쓰지 않고도 즉시 반영된 결과를 볼 수 있도록 패치 파트를 생성합니다. SELECT 쿼리에 오버헤드가 추가되지만 지연 시간은 예측 가능합니다. |
| Update mutation | ALTER TABLE [table] UPDATE | 더 큰 규모의 데이터 관리를 수행할 때 사용하십시오. 특히 업데이트가 테이블 파티셔닝과 잘 맞아떨어질 때 적합합니다. 예를 들어, 월 단위로 파티셔닝된 테이블에서 특정 월에 속한 모든 행의 컬럼 하나를 업데이트해야 하는 경우입니다. |
특수 테이블 엔진을 활용한 업데이트
ReplacingMergeTree
ReplacingMergeTree는 백그라운드 머지 과정에서 동일한 정렬 키를 가진 행을 중복 제거하여 최신 버전만 유지합니다.
FINAL 수정자 또는 이에 상응하는 쿼리 로직을 사용해야 합니다. FINAL 수정자는 데이터에 따라 21~550%의 쿼리 오버헤드를 추가합니다.
ReplacingMergeTree는 정렬 키 값을 업데이트할 수 없습니다. 또한 논리적 삭제를 위한 Deleted 컬럼도 지원합니다.
더 알아보기: ReplacingMergeTree 가이드 | ReplacingMergeTree 참고
CoalescingMergeTree
Nullable이어야 합니다. ReplacingMergeTree와 마찬가지로, 올바르게 병합된 결과를 얻으려면 FINAL을 사용하십시오.
이 엔진은 ClickHouse 25.6부터 사용할 수 있습니다.
자세히 보기: CoalescingMergeTree
CollapsingMergeTree
CollapsingMergeTree는 머지 중 행을 어떻게 처리할지 ClickHouse에 알리기 위해 Sign 컬럼을 사용합니다. Sign 컬럼에 -1이 삽입되면 해당 행은 대응되는 +1 행과 짝을 이룰 때 축약되어 삭제됩니다. 업데이트할 행은 테이블 생성 시 ORDER BY 절에서 사용한 정렬 키를 기준으로 식별됩니다.
ReplacingMergeTree와 달리 CollapsingMergeTree는 정렬 키 값을 수정할 수 있습니다. 금융 거래나 게임 상태 추적처럼 취소 semantics가 있는 되돌릴 수 있는 작업에 적합합니다.
위의 업데이트 방식에서는 취소 행을 삽입하기 위해 애플리케이션이 클라이언트 측에서 상태를 유지해야 합니다. 이 방식은 ClickHouse 관점에서 가장 효율적이지만, 대규모 환경에서는 다루기가 복잡할 수 있습니다. 또한 올바른 결과를 얻으려면 쿼리에서도 부호 곱셈을 포함한 집계가 필요합니다.
선언적 업데이트
뮤테이션
ALTER TABLE ... UPDATE)은 WHERE 표현식에 일치하는 행이 포함된 모든 파트를 재작성합니다.
WHERE 표현식과 일치하는 모든 파트를 다시 써야 하므로 I/O 부하가 큽니다.
이 과정에는 원자성이 없습니다.
파트는 준비되는 즉시 뮤테이션된 파트로 교체되므로, 뮤테이션이 진행되는 동안 실행을 시작한 SELECT 쿼리에서는 이미 뮤테이션된 파트의 데이터와 아직 뮤테이션되지 않은 파트의 데이터가 함께 조회될 수 있습니다.
진행 상태는 system.mutations 테이블에서 확인할 수 있습니다.
자세히 보기: ALTER TABLE UPDATE
온더플라이 뮤테이션
ALTER TABLE ... UPDATE를 통한 뮤테이션은 변경된 값이 쿼리에 반영되기까지 백그라운드 프로세스에서 뮤테이션이 적용될 때까지 기다려야 할 수 있습니다.
ClickHouse는 “온더플라이 뮤테이션”을 통해 이 동작을 바꿀 수 있는 방법을 제공합니다.
온더플라이 뮤테이션이 활성화되면 업데이트된 행은 즉시 업데이트된 것으로 표시되며, 이후 SELECT 쿼리는 변경된 값을 자동으로 반환합니다.
온더플라이 뮤테이션은 쿼리 수준 설정인 apply_mutations_on_fly를 활성화하면 MergeTree 계열 테이블에서 사용할 수 있습니다.
예시
예시
테이블을 생성하고 몇 가지 뮤테이션을 실행해 보겠습니다.새 테이블에 쿼리해도 아직은 행 값이 업데이트되지 않았음을 확인할 수 있습니다.이제 온더플라이 뮤테이션을 활성화했을 때 어떻게 되는지 살펴보겠습니다.이제
SELECT 쿼리로 업데이트 결과를 확인해 보겠습니다.SELECT 쿼리는 뮤테이션이 적용될 때까지 기다리지 않고도 즉시 올바른 결과를 반환합니다.성능 영향
SELECT 쿼리에서만 적용됩니다. 다만 뮤테이션은 여전히 백그라운드에서 비동기적으로 구체화되며, 이 과정은 부하가 큰 작업이라는 점에 유의하십시오.
일정 시간 동안 등록되는 뮤테이션 수가 백그라운드에서 처리되는 뮤테이션 수를 지속적으로 초과하면, 적용해야 할 미구체화 뮤테이션의 큐가 계속 증가합니다. 그 결과 결국 SELECT 쿼리 성능이 저하됩니다.
미구체화 뮤테이션이 무한정 증가하는 것을 제한하려면 apply_mutations_on_fly 설정을 number_of_mutations_to_throw, number_of_mutations_to_delay와 같은 다른 MergeTree 수준의 설정과 함께 활성화하는 것이 좋습니다.
서브쿼리 및 비결정적 함수 지원
mutations_max_literal_size_to_replace로 제어됩니다. 비결정적 함수는 상수인 경우에만 지원됩니다(예: 함수 now()).
이 동작은 다음 설정으로 제어됩니다:
| 설정 | 설명 | 기본값 |
|---|---|---|
mutations_execute_nondeterministic_on_initiator | true이면 비결정적 함수가 initiator 레플리카에서 실행되고 UPDATE 및 DELETE 쿼리에서는 리터럴로 대체됩니다. | false |
mutations_execute_subqueries_on_initiator | true이면 스칼라 서브쿼리가 initiator 레플리카에서 실행되고 UPDATE 및 DELETE 쿼리에서는 리터럴로 대체됩니다. | false |
mutations_max_literal_size_to_replace | UPDATE 및 DELETE 쿼리에서 대체할 직렬화된 리터럴의 최대 크기(바이트)입니다. | 16384 (16 KiB) |
경량 업데이트
UPDATE 구문을 사용하며, 머지를 기다리지 않고 즉시 패치 파트를 생성합니다. 업데이트된 값은 패치 적용을 통해 SELECT 쿼리에서 바로 확인할 수 있지만, 물리적으로는 이후 머지 과정에서만 구체화됩니다. 따라서 경량 업데이트는 예측 가능한 지연 시간으로 적은 비율의 행(테이블의 약 10% 이하)을 업데이트하는 경우에 적합합니다. 벤치마크 결과, 뮤테이션보다 최대 23배 더 빠를 수 있습니다.
반면, 패치를 적용할 때 SELECT 쿼리에 오버헤드가 발생하며, 패치 파트도 파트 제한 수에 포함됩니다. 약 10%의 임계값을 넘으면 읽기 시 패치 적용 오버헤드가 비례해 증가하므로, 더 큰 규모의 업데이트에는 동기식 뮤테이션이 더 효율적입니다.
자세히 보기: Lightweight UPDATE
온더플라이 뮤테이션
온더플라이 뮤테이션은 행을 업데이트할 때 백그라운드 처리가 끝날 때까지 기다리지 않아도, 이후SELECT 쿼리에서 변경된 값을 자동으로 반환할 수 있게 해줍니다. 이는 일반 뮤테이션의 원자성 한계를 효과적으로 해결합니다.
SELECT 쿼리 모두에서 apply_mutations_on_fly = 1 설정이 활성화되어 있어야 합니다. 뮤테이션 조건은 ClickHouse Keeper에 저장되며, Keeper는 모든 것을 메모리에 유지하고 쿼리 실행 중 온더플라이로 이를 적용합니다.
뮤테이션은 여전히 데이터를 업데이트하는 데 사용되며, 단지 즉시 구체화되지 않을 뿐입니다. 뮤테이션은 비동기 프로세스로 백그라운드에서 계속 적용되며, 일반 뮤테이션과 마찬가지로 큰 오버헤드가 발생합니다. 또한 이 작업에 사용할 수 있는 표현식도 제한적입니다(자세한 내용 참조).
자세히 보기: 온더플라이 뮤테이션
비교 요약
| 방법 | 쿼리 속도 저하 | 메모리 오버헤드 | 참고 사항 |
|---|---|---|---|
| 뮤테이션 | 기준선 | 기준선 | 완료 후 최대 속도; 데이터가 물리적으로 다시 기록됨 |
| 온더플라이 뮤테이션 | 가변적 | 가변적 | 즉시 반영됨; 업데이트가 많이 누적되면 성능이 저하됨 |
| 경량 업데이트 | 7–18% (평균 약 12%) | +20–210% | 쿼리 측면에서 가장 효율적임; 테이블의 10% 이하를 업데이트할 때 가장 적합함 |
ReplacingMergeTree + FINAL | 21–550% (평균 약 280%) | 기준선 대비 20–200배 | 모든 행 버전을 읽어야 함; 쿼리 오버헤드가 가장 큼 |
CoalescingMergeTree + FINAL | ReplacingMergeTree와 유사 | ReplacingMergeTree와 유사 | 컬럼 수준 coalescing으로 비슷한 수준의 오버헤드가 발생함 |
| CollapsingMergeTree | 집계에 따라 달라짐 | 집계에 따라 달라짐 | 오버헤드는 쿼리 복잡도에 따라 달라짐 |