본문으로 건너뛰기
최종 수정: 에

Merge-on-Write

Merge-on-write와 merge-on-read는 Unique Key 모델의 두 가지 스토리지 구현 방식입니다. 두 방식 모두 Key 컬럼의 고유성을 유지하고 동일한 쿼리 결과를 반환하지만, 중복 Key를 처리하는 시점이 달라 읽기 및 쓰기 성능에 차이가 있습니다. 기본값인 Merge-on-write는 대부분의 워크로드에 가장 적합합니다.

비교​

구현 방식병합 시점쓰기 성능쿼리 성능적합한 시나리오
Merge-on-write(기본값)쓰기 시점보통높음쿼리와 쓰기 성능의 균형이 필요한 대부분의 시나리오
Merge-on-read쿼리 또는 compaction 시점높음상대적으로 낮음쓰기가 많고 읽기가 적은 시나리오

Merge-on-Write의 작동 방식​

merge-on-write 방식에서는 Doris가 데이터를 쓰는 시점에 중복 Key를 처리합니다. 새로 들어오는 각 행에 대해 해당 Key가 이미 존재하는지 확인하고, 기존 버전이 있으면 delete bitmap에 삭제된 것으로 표시합니다. 쿼리는 이 비트맵을 사용해 표시된 행을 건너뛰므로 최신 버전만 읽습니다. 이후 compaction 과정에서 해당 행이 디스크에서 제거됩니다.

쓰기 시점에 중복을 처리하므로 다음과 같은 이점이 있습니다.

  • 쿼리는 Key마다 하나의 버전만 읽으며, 읽기 시점에 병합할 필요가 없습니다.
  • Doris는 필터를 스토리지 계층으로 푸시다운할 수 있으므로, 스캔 시 조건에 맞지 않는 데이터를 건너뜁니다.
  • 과거 업데이트가 누적되어도 읽기 성능이 저하되지 않습니다.

대신 쓰기 측에 비용이 발생합니다. 각 upsert는 기본 키를 조회해 이전 버전을 찾아 표시하므로, merge-on-read에 비해 쓰기 오버헤드가 다소 늘어납니다. 대부분의 워크로드에서는 이러한 비용보다 이점이 크므로 merge-on-write가 기본값입니다.

Merge-on-Read의 작동 방식​

merge-on-read 방식에서는 쓰기 작업이 데이터를 추가하기만 합니다. Doris는 Key의 모든 버전을 유지하고, 쿼리 시점이나 compaction 과정에서 이를 병합해 최신 버전을 반환합니다.

읽기 시점에 중복을 처리하므로 다음과 같은 특성이 있습니다.

  • 기본 키 조회를 생략하므로 쓰기 작업의 부담이 적습니다.
  • 모든 쿼리에서 각 Key의 버전을 병합해야 하고, Doris가 필터를 푸시다운할 수 없어 쿼리가 느려집니다.
  • compaction 사이에 버전이 누적될수록 쿼리 지연 시간이 늘어납니다.

따라서 쿼리 속도보다 쓰기 처리량이 중요하고, 쓰기가 많으며 읽기가 적은 파이프라인에 적합합니다.

선택 기준​

  • 실시간 업데이트, 차원 데이터 동기화 등 쿼리 성능이 중요한 경우를 포함한 대부분의 워크로드에는 merge-on-write(기본값)를 사용하세요. 이 방식은 부분 컬럼 업데이트와 같은 기능도 지원합니다.
  • 읽기보다 쓰기가 훨씬 많고 쓰기 오버헤드를 최소화해야 하는 경우에만 merge-on-read를 사용하세요.

구현 방식은 테이블 생성 시 고정되며 나중에 스키마 변경으로 바꿀 수 없으므로, 테이블을 생성하기 전에 결정해야 합니다.

각 구현 방식 활성화​

enable_unique_key_merge_on_write 테이블 속성으로 구현 방식을 제어합니다.

Merge-on-write(기본값):

CREATE TABLE IF NOT EXISTS example_tbl_unique
(
user_id LARGEINT NOT NULL,
user_name VARCHAR(50) NOT NULL,
city VARCHAR(20),
age SMALLINT,
sex TINYINT
)
UNIQUE KEY(user_id, user_name)
DISTRIBUTED BY HASH(user_id) BUCKETS 10
PROPERTIES (
"enable_unique_key_merge_on_write" = "true"
);

Merge-on-read(속성을 false로 설정):

CREATE TABLE IF NOT EXISTS example_tbl_unique
(
user_id LARGEINT NOT NULL,
user_name VARCHAR(50) NOT NULL,
city VARCHAR(20),
age SMALLINT,
sex TINYINT
)
UNIQUE KEY(user_id, user_name)
DISTRIBUTED BY HASH(user_id) BUCKETS 10
PROPERTIES (
"enable_unique_key_merge_on_write" = "false"
);

Merge-on-Write가 필요한 기능​

부분 컬럼 업데이트에는 merge-on-write가 필요합니다. 이 기능은 전체 행을 다시 쓰지 않고 일부 컬럼만 업데이트합니다.