← 학습 카테고리

Learn

ClickHouse

47개 모듈 · 현재 9번째

ClickHouse 모듈 9/47 clickhouse-learn-09

코덱과 인코딩 — 왜 압축률이 이렇게 높은가

ClickHouse 코덱/인코딩 및 Projection/EXPLAIN 공식 문서·기술 블로그 종합 (웹 리서치, 2026) — ClickHouse 공식 문서(data-modeling/projections) + Altinity/ChistaData 등 기술 블로그 종합 ClickHouse 공식 블로그 'Optimizing ClickHouse with Schemas and Codecs' 및 Altinity 인코딩 가이드

이 모듈을 다 읽으면

  • 인코딩(도메인 특화 변환)과 압축(범용 바이트 압축)이 2단계로 분리돼 있다는 것을 설명할 수 있다
  • Delta/DoubleDelta/Gorilla 인코딩이 각각 어떤 데이터 패턴에 맞는지 구분할 수 있다
  • LowCardinality가 문자열 컬럼의 저장·집계 성능을 어떻게 개선하는지 설명할 수 있다

clickhouse-learn-01에서 다룬 '컬럼 지향이라 압축률이 높다'는 개념을 넘어, 실제로 어떤 인코딩·압축 코덱을 쓰는지, 그리고 LowCardinality 타입이 문자열 컬럼에 어떤 이점을 주는지 정리한다.

2단계 파이프라인 — 인코딩 다음에 압축

ClickHouse는 컬럼 데이터를 저장할 때 두 단계를 거친다. 먼저 인코딩(encoding) 단계에서 값의 '범위'를 줄이는 도메인 특화 변환을 적용하고(예: 연속된 값의 차이만 저장), 그 다음 압축(compression) 단계에서 LZ4/ZSTD 같은 범용 바이트 압축 알고리즘을 적용한다. 인코딩이 먼저 값의 패턴을 압축하기 쉬운 형태로 바꿔주기 때문에, 인코딩 없이 압축만 하는 것보다 훨씬 높은 압축률을 얻을 수 있다. 컬럼마다 CODEC(...) 절로 이 파이프라인을 지정할 수 있다.

핵심 포인트

  • 인코딩(도메인 특화, 값의 범위를 줄임) → 압축(범용 바이트 압축) 2단계 파이프라인
  • 인코딩이 먼저 압축하기 쉬운 형태로 바꿔줘서 인코딩 없이 압축만 할 때보다 압축률이 훨씬 높아진다

인코딩 코덱 — 데이터 패턴에 맞춰 고른다

Delta는 연속된 값의 '차이'만 저장한다 — 단조 증가하는 값(예: 계속 커지는 ID, 타임스탬프)에 적합해, 큰 절대값 대신 작은 차이값들만 남아 압축이 잘 된다. DoubleDelta는 '차이의 차이'(2차 차분)를 저장한다 — 일정한 간격으로 증가하는 시계열 타임스탬프처럼 델타 자체가 거의 일정한 데이터에 특히 효과적이다. Gorilla는 현재 값과 이전 값의 XOR을 저장한다 — 천천히 변하는 부동소수점 값(온도, CPU 사용률 같은 메트릭)에 적합하다. 이런 인코딩은 데이터의 실제 패턴과 맞을 때만 효과가 크므로, 무작정 다 적용하기보다 컬럼의 실제 값 분포를 보고 골라야 한다.

핵심 포인트

  • Delta: 연속값의 차이 저장 — 단조 증가 데이터(ID, 타임스탬프)에 적합
  • DoubleDelta: 차이의 차이 저장 — 일정 간격 시계열 타임스탬프에 특히 효과적
  • Gorilla: 이전 값과의 XOR 저장 — 천천히 변하는 부동소수점 메트릭에 적합

압축 코덱 — LZ4 vs ZSTD

인코딩 뒤에는 범용 압축 코덱이 적용된다. LZ4가 기본값으로, 빠른 압축·해제 속도에 적당한 압축률을 제공한다. ZSTD는 레벨(1~22, 기본 1)을 조절할 수 있어 더 높은 압축률을 낼 수 있지만 그만큼 CPU를 더 쓴다 — 실무에서는 레벨 3 정도가 속도와 압축률의 합리적인 절충점으로 언급된다. 시계열 데이터라면 DoubleDelta(또는 Delta) + ZSTD(1) 조합이, 천천히 변하는 부동소수점 메트릭이라면 Gorilla + LZ4(디코딩 속도 우선) 조합이 흔히 추천된다.

핵심 포인트

  • LZ4(기본): 빠른 속도, 적당한 압축률 / ZSTD(레벨 1~22, 기본 1): 더 높은 압축률, CPU 더 사용
  • 추천 조합: 시계열=DoubleDelta+ZSTD(1), 천천히 변하는 부동소수점=Gorilla+LZ4

LowCardinality — 문자열 컬럼을 딕셔너리로

distinct 값 종류가 적은(경험칙 1만 개 미만) 문자열 컬럼(예: country, status, log_level)에 LowCardinality(String)을 쓰면, 실제 문자열 값은 딕셔너리에 한 번만 저장하고 각 행에는 그 딕셔너리를 가리키는 작은 정수 인덱스만 저장한다(딕셔너리 인코딩). 이 덕분에 저장 공간이 3~10배 줄어들 뿐 아니라, GROUP BY 같은 집계 연산도 문자열 비교 대신 정수 비교로 처리돼 훨씬 빨라진다. 다만 distinct 값이 매우 많은 컬럼(예: user_id 같은 고카디널리티)에는 딕셔너리 자체가 커져 오히려 역효과가 날 수 있어 적합하지 않다.

핵심 포인트

  • LowCardinality(String) = 문자열을 딕셔너리로 저장하고 각 행엔 정수 인덱스만 저장(딕셔너리 인코딩)
  • 저장 공간 3~10배 절감 + GROUP BY 등 집계가 정수 비교로 처리돼 빨라짐
  • distinct 값이 적을 때(경험칙 1만 개 미만)만 효과적 — 고카디널리티 컬럼에는 부적합