병합 선택 알고리즘 — 어떤 Part를 먼저 합칠지 결정하는 기준
ClickHouse 병합 선택 알고리즘 및 Buffer 테이블 엔진 공식 문서 종합 (웹 리서치, 2026) — ClickHouse 공식 문서(merges, engines/table-engines/special/buffer) ClickHouse 공식문서 Part merges
이 모듈을 다 읽으면
- clickhouse-learn-02의 백그라운드 병합이 '무작위'가 아니라 파티션 경계·크기 기준의 알고리즘으로 Part를 선택한다는 것을 설명할 수 있다
- Part의 병합 레벨(merge level)이 무엇을 의미하는지, 병합된 Part의 목표 크기 상한이 왜 존재하는지 설명할 수 있다
clickhouse-learn-02에서 다룬 'Part는 백그라운드에서 계속 병합된다'는 사실을 전제로, 그 병합이 실제로 어떤 Part들을 우선적으로 골라 합치는지를 지배하는 선택 알고리즘의 기준을 정리한다.
병합은 항상 같은 파티션 안에서만 일어난다
clickhouse-learn-03에서 다룬 PARTITION BY 설계의 핵심 규칙을 병합 관점에서 다시 보면 이렇다 — ClickHouse는 (파티션별로) 작은 Part들을 백그라운드에서 계속 더 큰 Part로 합쳐 나가는데, 이 병합은 압축된 크기가 대략 150GB 정도에 이를 때까지 같은 파티션 안에서만 계속된다. 파티션 경계를 넘는 병합은 애초에 고려 대상이 아니다 — 그래서 파티션 키를 지나치게 잘게 쪼개면(카디널리티가 너무 높으면) 파티션마다 Part가 흩어져 병합이 제대로 안 일어나고, 이것이 clickhouse-learn-07의 'Too Many Parts' 문제로 이어지는 원인 중 하나다.
핵심 포인트
- 병합은 항상 같은 파티션 안에서만 일어나고, 압축 크기 약 150GB 정도까지 계속 더 큰 Part로 합쳐짐
- 파티션 경계를 넘는 병합은 없음 — 파티션 키 카디널리티가 너무 높으면 파티션마다 Part가 흩어져 병합이 잘 안 되고 'Too Many Parts'로 이어질 수 있음
Part의 병합 레벨(merge level) — 몇 번 합쳐졌는지의 기록
각 Part는 자신이 몇 번 병합을 거쳤는지를 나타내는 '병합 레벨'을 갖는다 — 레벨 0은 아직 한 번도 병합된 적 없는 새 Part(예: 방금 INSERT로 생긴 Part)를 뜻하고, 추가로 병합될 때마다 레벨이 하나씩 올라간다. 즉 레벨이 낮은 Part일수록 '아직 안 합쳐진 신선한 조각'이고, 레벨이 높을수록 여러 번의 병합을 거쳐 누적된 결과물이라는 뜻이다. 병합 선택 알고리즘은 이런 신선한(레벨 낮은) Part들을 우선적으로 골라 합쳐 Part 개수를 빠르게 줄이는 방향으로 동작한다.
핵심 포인트
- 병합 레벨 0 = 아직 병합된 적 없는 새 Part, 추가 병합마다 레벨 +1
- 레벨이 낮은(신선한) Part를 우선적으로 골라 병합해 Part 개수를 빠르게 줄이는 방향으로 선택 알고리즘이 동작
왜 이 구조를 알아야 하는가 — 쓰기 증폭과 Part 개수의 트레이드오프
백그라운드 병합 스레드 풀은 서버 설정(동시 병합·뮤테이션 작업 수)으로 제어되는데, 병합 선택 알고리즘은 근본적으로 두 상충하는 목표 사이에서 균형을 잡아야 한다 — 같은 데이터를 반복해서 재작성하는 '쓰기 증폭(write amplification)'을 제한하는 것과, 읽기 성능을 해치는 'Part 개수'를 제한하는 것. 이 균형점을 이해하면 clickhouse-learn-07의 배치 인서트 원칙(초당 ~1회, 1000~10만 행 단위)이 왜 '병합 알고리즘이 감당 가능한 속도로 Part를 만들어주는 것'인지가 명확해진다 — 너무 잦은 소량 INSERT는 병합 알고리즘이 아무리 잘 작동해도 Part 생성 속도를 못 따라가게 만든다.
핵심 포인트
- 병합 선택 알고리즘은 '쓰기 증폭 제한' vs 'Part 개수 제한'이라는 상충하는 두 목표 사이에서 균형을 잡음
- clickhouse-learn-07의 배치 인서트 원칙(초당 ~1회 등)은 결국 병합 알고리즘이 감당 가능한 속도로 Part를 만들어주기 위한 것