데이터 업데이트 및 삭제
요약 Apache Doris는 트랜잭션 데이터베이스처럼 SQL
UPDATE와DELETE를 지원하며, 스트리밍 데이터 적재를 통한 부분 열 업서트, 조건자 기반 일괄 삭제, 원자적 파티션 교체도 지원합니다. Unique Key 테이블에서는 Merge-on-Write 엔진이 읽기 시점에 버전을 병합하는 대신 쓰기 시점에 rowset별 비트맵에 삭제된 행을 표시하여 쿼리 지연 시간을 낮게 유지합니다. Merge-on-Write는 버전 2.1부터 Unique Key의 기본값이 되었습니다.

Apache Doris에서 데이터 업데이트 및 삭제를 사용하는 이유는 무엇인가요?
Apache Doris의 데이터 업데이트 및 삭제 기능은 분석 엔진에서 트랜잭션 방식의 행 단위 변경을 지원합니다. 따라서 CDC, GDPR에 따른 삭제, 일회성 수정을 처리할 때 파티션 전체를 다시 쓰지 않아도 됩니다. 대부분의 분석 엔진은 데이터 웨어하우스에 데이터를 추가하기만 한다는 전제로 설계되었습니다. 이후 CDC와 GDPR이 등장했고, 운영 데이터에는 오류가 있다는 평범한 사실도 마주하게 되었습니다. 데이터 웨어하우스에서 잘못된 행 하나를 고치려면 파티션 전체를 다시 써야 한다면, 뒤늦게 도착하는 수정 사항마다 운영팀에 작업을 요청해야 합니다.
- Flink CDC 작업이 MySQL을 모니터링하며, 모든 행 업데이트를 수초 안에 반영해야 합니다.
- 사용자가 GDPR에 따라 삭제를 요청합니다. 데이터 웨어하우스에서 해당 데이터를 삭제해야 하며, "다음 compaction 이후에 삭제"되어서는 안 됩니다.
- 행 수가 십억의 10배인 팩트 테이블에서 행 하나에 오타가 있어 보고서에 잘못된 수치가 표시됩니다.
Apache Doris는 UPDATE, DELETE FROM ... WHERE, Stream Load를 통한 부분 열 업서트, 대량 정리를 위한 TRUNCATE 또는 원자적 파티션 교체와 같은 정식 SQL 기능으로 이 세 가지 상황을 모두 처리합니다. 어느 기능도 테이블 크기가 작아야 한다는 제약이 없으며, 이후에 사용자가 별도의 재작성 작업을 예약할 필요도 없습니다.
Apache Doris의 데이터 업데이트 및 삭제란 무엇인가요?
Apache Doris의 데이터 업데이트 및 삭제 기능은 UPDATE SQL, 조건자 DELETE, 부분 열 업서트, 파티션 교체라는 네 가지 기능으로 구성되며, Unique Key 테이블의 Merge-on-Write 엔진을 기반으로 동작합니다. 행 단위 UPDATE SQL은 Unique Key 테이블에서 동작하고, 조건자 기반 DELETE FROM ... WHERE는 모든 테이블에서 동작합니다. 부분 열 업서트는 데이터 적재를 통해 수행되며, Stream Load의 partial_columns: true 헤더 또는 이에 대응하는 세션 변수를 사용합니다. 파티션 단위 작업에는 TRUNCATE PARTITION과 임시 파티션을 이용한 원자적 교체가 포함됩니다. 내부적으로 Unique Key 모델은 Merge-on-Write(MoW)를 사용하므로 삭제와 업데이트가 쿼리 시점이 아닌 쓰기 시점에 적용됩니다. MoW는 1.2에서 도입되었으며, 2.1부터 Unique Key의 기본값이 되었습니다.
주요 용어
Unique Key model: 기본 키마다 하나의 행을 유지하는 테이블 모델입니다.UPDATE와 일괄 업서트에 필요합니다.Merge-on-Write (MoW): 쓰기 시점에 Apache Doris가 기존 데이터에서 각 새 키를 조회하고, 이전 행을 삭제 비트맵에 표시한 뒤, 새 행을 새로운 rowset에 기록하는 방식입니다.Delete bitmap: 쿼리에서 건너뛰어야 할 행 ID를 담는 rowset별 비트맵으로, 읽기 시점의 키별 버전 병합을 대체합니다.Partial column update: 일부 열만 변경하는 쓰기 작업입니다. Apache Doris는 기존 행에서 누락된 값을 읽어 완전한 행을 다시 기록합니다.Sequence column(function_column.sequence_col): 순서가 뒤바뀐 쓰기가 도착했을 때 MoW가 동일한 키의 어느 버전을 선택할지 판단하도록 사용자가 지정하는 열입니다.__DORIS_DELETE_SIGN__: 어떤 데이터 적재 경로에서든1로 설정하면 행을 논리적으로 삭제할 수 있는 숨겨진 열입니다.
Apache Doris의 데이터 업데이트 및 삭제는 어떻게 동작하나요?
Apache Doris의 데이터 업데이트 및 삭제는 Unique Key MoW 테이블에서 다섯 단계로 진행됩니다. 실행 계획 수립 및 읽기, 키 조회, 이전 행의 삭제 비트맵 비트 설정, 새로운 rowset에 새 행 쓰기, 새 버전 공개 순서입니다.
Unique Key MoW 테이블에 대한 UPDATE를 예로 살펴보겠습니다.
- 실행 계획 수립 및 읽기. FE가 구문을 파싱하고 WHERE 조건자를 해석한 뒤, BE 복제본에 읽기 요청을 분산합니다. 부분 열 쓰기에서는 각 BE가 변경 대상 키에 대해 누락된 열 값도 추가로 가져옵니다.
- 키 조회. 각 BE가 rowset별 메모리 내 기본 키 인덱스를 조회하여 변경 대상 키가 현재 어느 rowset의 어떤 행 ID에 있는지 찾습니다.
- 이전 행 표시. 변경 대상 키를 포함하는 모든 rowset에서 해당 행 ID에 대응하는 삭제 비트맵 비트를 켭니다. 이전 행은 compaction으로 정리될 때까지 디스크에 남아 있습니다.
- 새 행 쓰기. 새 값과 함께, 부분 업데이트를 위해 Apache Doris가 읽어야 했던 변경되지 않은 열 값도 다음 버전 번호를 가진 새로운 rowset에 기록됩니다.
- 공개. 트랜잭션이 커밋되면 새 버전이 표시되고, 이후의 쿼리는 병합된 삭제 비트맵을 통해 행을 필터링합니다. 이전 데이터의 공간은 compaction 시 회수됩니다.
DELETE FROM ... WHERE도 쓰기 단계를 제외하면 같은 흐름을 따릅니다. Aggregate 또는 Duplicate 테이블에서는 Apache Doris가 대신 tablet 메타데이터에 조건자를 기록하고, 쿼리가 읽기 시점에 이를 적용합니다.
빠른 시작
CREATE TABLE orders (
order_id BIGINT,
status VARCHAR(20),
amount DECIMAL(10, 2),
updated DATETIME
)
UNIQUE KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 4
PROPERTIES ("function_column.sequence_col" = "updated");
INSERT INTO orders VALUES
(1, 'created', 99.50, '2026-05-08 10:00:00'),
(2, 'created', 149.00, '2026-05-08 10:01:00');
UPDATE orders SET status = 'shipped', updated = NOW() WHERE order_id = 1;
DELETE FROM orders WHERE order_id = 2;
예상 결과
+----------+---------+--------+---------------------+
| order_id | status | amount | updated |
+----------+---------+--------+---------------------+
| 1 | shipped | 99.50 | 2026-05-08 11:42:31 |
+----------+---------+--------+---------------------+
주문 1은 제자리에서 다시 쓰였고, 주문 2는 삭제되었습니다. function_column.sequence_col 속성은 순서가 뒤바뀐 쓰기로부터 테이블을 보호합니다. 더 오래된 updated 타임스탬프를 가진 CDC 이벤트는 더 최신인 행보다 나중에 도착하더라도 이미 존재하는 행을 덮어쓰지 못합니다.
Apache Doris의 데이터 업데이트 및 삭제는 언제 사용해야 하나요?
Apache Doris의 데이터 업데이트 및 삭제는 Unique Key 테이블로의 CDC 업서트, 넓은 테이블에서 자주 변경되는 열의 업데이트, GDPR에 따른 행 단위 삭제, 원자적 백필 교체, 여러 스트림을 통한 넓은 테이블 구성에 적합합니다. Aggregate 또는 Duplicate 테이블에 대한 UPDATE, 짧은 반복문에서 연속으로 실행하는 단일 행 업데이트, 기본 키 변경, 파티션 교체로 한 번에 처리할 수 있는 대규모 조건자 DELETE에는 적합하지 않습니다.
적합한 경우
- 소스 기본 키를 Apache Doris의 키로 사용하여 Unique Key 테이블에 업서트하는 Flink 및 Spark CDC 파이프라인.
- 부분 열 Stream Load를 통해 넓은 테이블에서 자주 변경되는 열(주문 상태, 마지막 확인 타임스탬프, 현재 잔액)을 업데이트하는 경우.
- 추가만 가능한 Duplicate 테이블을 포함하여, 사용자 ID를 기준으로 GDPR에 따라 행 단위로 삭제하는 경우.
ALTER TABLE ... REPLACE PARTITION으로 수정된 파티션을 원자적으로 교체하는 백필 작업.- 각 업스트림이 특정 열 그룹을 담당하고 자신의 열만 기록하는 방식으로 여러 스트림을 통해 넓은 테이블을 구성하는 경우.
적합하지 않은 경우
- Aggregate 또는 Duplicate 테이블에 대한
UPDATE. 이 구문은 거부됩니다. 데이터 적재를 통해 다시 로드하거나(Aggregate는REPLACE_IF_NOT_NULL을 사용하여 값을 덮어씁니다), 테이블 모델을 변경하세요. - 짧은 반복문에서 빈번하게 실행하는 단일 행
UPDATE. 각 구문이 별도의 트랜잭션이므로 커밋 오버헤드가 대부분의 비용을 차지합니다. 대신 Stream Load에서partial_columns: true를 사용하여 일괄 업데이트하거나, Group Commit을 사용하세요. - 기본 키 변경. 키를 다시 쓰는 경로는 없습니다.
__DORIS_DELETE_SIGN__으로 이전 행을 논리적으로 삭제하고 새 행을 삽입하세요. 가능하면 동일한 데이터 적재에서 수행하는 것이 좋습니다. - 일치하는 행이 수십억 개에 이르는 조건자
DELETE. 각 삭제는 compaction에서 처리해야 하는 조건자나 비트맵을 기록하므로, 파티션 교체나INSERT OVERWRITE가 더 빠릅니다. - Aggregate 모델에서 키가 아닌 열에 대한
DELETE. 조건자는 키 열만 필터링해야 합니다. 엔진은 집계 전에 값 열의 조건을 평가할 수 없습니다.
더 읽어보기
- 데이터 업데이트 및 삭제 개요
- 업데이트 개요: SQL UPDATE, 부분 열 업데이트, Sequence 열
- 부분 열 업데이트
- 삭제 개요: 조건자 삭제, 일괄 삭제, 원자적 교체
- 데이터 모델: Unique Key가 UPDATE/DELETE를 지원하는 테이블 모델인 이유와 Duplicate 및 Aggregate가 적합한 용도를 설명합니다.
- 높은 동시성 포인트 쿼리: Unique Key Merge-on-Write 테이블에서 KV 방식의 읽기에 사용할 수 있는 단축 실행 경로를 설명합니다.
- Binlog 테이블 스트림: 커밋된 행 단위 변경 사항이 다운스트림 소비자에게 어떻게 제공되는지 설명합니다.
- Apache Doris 2.1.0: Merge-on-Write가 Unique Key의 기본값으로 지정
- Unique Key: SQL UPDATE/DELETE를 지원하는 테이블 모델입니다. Merge-on-Write는 쓰기 시점에 각 업서트를 처리합니다.