`OPTIMIZE FINAL`은 피하세요

OPTIMIZE FINAL은 피하세요

OPTIMIZE FINAL은 모든 활성 파트를 하나로 강제로 병합하는 리소스 집약적 작업이라, 대부분의 경우 클러스터 성능에 악영향을 줍니다. 이 문서에서는 왜 피해야 하는지, 그리고 대신 어떤 방법을 써야 하는지 설명할게요.

출처: 문서

본문

MergeTree 엔진을 사용하는 ClickHouse 테이블은 데이터를 디스크에 변경 불가능한 파트(immutable parts) 로 저장하며, 데이터를 삽입할 때마다 새 파트가 만들어집니다. 각 삽입은 정렬되고 압축된 컬럼 파일과 함께 인덱스, 체크섬 같은 메타데이터를 포함한 새 파트를 생성하죠. 파트 구조와 형성 과정에 대한 자세한 설명은 이 가이드를 추천합니다. 시간이 지나면 백그라운드 프로세스가 작은 파트들을 더 큰 파트로 병합하여 단편화를 줄이고 쿼리 성능을 개선합니다.

수동으로 병합을 트리거하는 것이 유혹적일 수 있습니다:

OPTIMIZE TABLE <table> FINAL;

하지만 대부분의 경우 OPTIMIZE FINAL 연산은 피해야 합니다. 리소스 집약적인 작업을 시작해 클러스터 성능에 영향을 줄 수 있기 때문입니다.

OPTIMIZE FINAL과 FINAL의 차이 OPTIMIZE FINALFINAL과는 다릅니다. FINALReplacingMergeTree처럼 중복 없이 결과를 얻기 위해 가끔 필요한 쿼리 수식어죠. 일반적으로 쿼리가 프라이머리 키와 동일한 컬럼으로 필터링한다면 FINAL은 사용해도 괜찮습니다.

왜 피해야 하나요?

비용이 많이 듭니다

OPTIMIZE FINAL을 실행하면 ClickHouse는 큰 병합이 이미 일어났더라도 모든 활성 파트를 단일 파트 로 강제 병합합니다. 여기에는 다음이 포함됩니다:

  1. 모든 파트 압축 해제
  2. 데이터 병합
  3. 다시 압축
  4. 최종 파트를 디스크나 오브젝트 스토리지에 쓰기

이 단계들은 CPU와 I/O 집약적이며, 특히 대규모 데이터셋에서는 시스템에 상당한 부담을 줍니다.

안전 한도를 무시합니다

일반적으로 ClickHouse는 약 150 GB보다 큰 파트 병합을 피합니다(max_bytes_to_merge_at_max_space_in_pool로 설정 가능). 하지만 OPTIMIZE FINAL이 안전장치를 무시합니다. 즉:

  • 여러 개의 150 GB 파트를 하나의 거대한 파트로 병합하려 할 수 있습니다
  • 이로 인해 긴 병합 시간, 메모리 압박, 심지어 메모리 부족(OOM) 오류가 발생할 수 있습니다
  • 이렇게 큰 파트는 이후 병합이 어려워집니다. 즉, 위에서 말한 이유 때문에 계속 병합하려는 시도가 실패합니다. 쿼리 시점의 올바른 동작을 위해 병합이 필요한 경우, ReplacingMergeTree에서 중복이 누적되는 등의 바람직하지 않은 결과를 초래해 쿼리 성능이 저하될 수 있습니다.

백그라운드 병합에 맡기세요

ClickHouse는 이미 저장 공간과 쿼리 효율을 최적화하는 스마트한 백그라운드 병합을 수행합니다. 이 병합은 점진적이고, 리소스를 인식하며, 설정된 임계값을 준수합니다. 아주 특별한 필요(예: 테이블을 동결하기 전이나 내보내기 전에 데이터를 확정)가 아니라면 ClickHouse가 병합을 스스로 관리하도록 두는 것이 낫습니다.

더 알아보기 (Learn more)