JSON 컬럼 타입은 ClickHouse 25.3+부터 프로덕션 환경에서 사용할 수 있습니다. 이전 버전은 프로덕션 용도로 권장되지 않습니다.
빠른 결정
- 모든 필드에 알려져 있고 안정적인 타입이 있으며 스키마가 거의 변경되지 않는다면 → 타입이 지정된 컬럼
- 대부분의 필드는 안정적이지만 일부 섹션은 동적이거나 예측하기 어렵다면 → Hybrid (typed + JSON)
- 전체 구조가 동적이고, 레코드마다 나타났다 사라지는 키가 있다면 → 네이티브 JSON 컬럼
- 동적 필드가 일관된 값 타입(예: 문자열 태그, 숫자 메트릭)을 가진 key-value 쌍이라면
→ JSON 대신
Map - 필드 수준 쿼리 없이 JSON blob만 저장하고 조회한다면 → 불투명 String 저장
JSON 포맷과 JSON 컬럼 타입을 혼동하지 마십시오.
JSON 컬럼 타입을 전혀 사용하지 않고도 JSON 형식의 데이터를 (JSONEachRow 등을 통해) 타입이 지정된 컬럼에 삽입할 수 있습니다. 여기서의 결정은 입력 형식이 아니라 컬럼 타입에 관한 것입니다.접근 방식 상세 정보
타입이 지정된 컬럼
Array, Tuple, Nested 타입으로 표현할 수 있습니다.
트레이드오프: 스키마 변경 시 ALTER TABLE이 필요합니다. 또한 스키마를 업데이트하지 않으면 예상하지 못한 필드는 삽입 시 조용히 삭제됩니다.
설정, 검증 및 주의사항
설정, 검증 및 주의사항
설정검증주의할 점
JSONEachRow로 JSON 데이터를 삽입할 때 JSON에 스키마에 없는 필드가 포함되어 있으면, ClickHouse는 기본적으로 해당 필드를 조용히 삭제합니다. 대신 오류가 발생하게 하려면input_format_skip_unknown_fields를0으로 설정하십시오.
Hybrid (타입이 지정된 컬럼 + JSON)
설정, 검증 및 주의사항
설정, 검증 및 주의사항
설정검증주의할 점
- 미리 파악하고 있는 JSON 경로에는 타입 힌트를 사용하십시오. 힌트는 판별자 컬럼을 우회하고 해당 경로를 일반적인 타입이 지정된 컬럼처럼 저장하므로, 동일한 성능을 제공하면서 오버헤드가 없습니다.
- 쿼리하지 않는 경로(디버그 메타데이터, 내부 tracing ID)에는
SKIP또는SKIP REGEXP를 사용해 저장 공간을 절약하고 서브컬럼 수를 줄이십시오. max_dynamic_paths는 실제로 쿼리하는 distinct paths 수에 비례하도록 설정하십시오. 기본값(1024)은 대부분의 경우에 적합합니다. 동적 영역이 작다면 이 값을 낮추십시오.max_dynamic_paths를 10,000보다 크게 설정하지 마십시오. 값이 너무 크면 리소스 활용이 늘고 효율이 떨어집니다.
점이 포함된 키점이 포함된 키(예:
http.status_code)는 기본적으로 중첩 경로로 처리되므로, {"http.status_code": 200}는 {"http": {"status_code": 200}}와 동일하게 저장됩니다. 이는 OTel 속성에서 흔히 볼 수 있습니다. 점이 포함된 경로를 어떻게 저장할지 제어하려면 타입 힌트를 사용하거나 json_type_escape_dots_in_keys (25.8+)를 활성화하십시오.네이티브 JSON 컬럼
설정, 검증 및 주의사항
설정, 검증 및 주의사항
설정JSON 컬럼에 JSON 문서 전체를 삽입할 때는 주의할 점
JSONAsObject 포맷을 사용합니다. 이 포맷은 각 입력 줄을 컬럼에 매핑되는 완전한 JSON 객체로 처리합니다.검증- 타입 힌트가 없으면 ClickHouse는 먼저 확인한 값을 기준으로 경로별 타입을 추론합니다. 한 레코드에서
score가"10"(문자열)으로 들어오고 다른 레코드에서는10(정수)으로 들어오면 해당 경로에 판별자 컬럼이 생성되어 쿼리가 더 느려집니다. 타입이 알려진 경로에는 힌트를 추가하십시오. - 경로 수가
max_dynamic_paths를 초과하면 오버플로우 값이 쿼리 성능이 낮은 공유 데이터 구조로 이동합니다.JSONDynamicPaths()로 모니터링하고 제한값은 10,000 미만으로 유지하십시오. - 각 동적 경로는 최대
max_dynamic_types(기본값 32)개의 고유 데이터 타입을 지원합니다. 단일 경로가 이를 초과하면 추가 타입은 공유 Variant 저장소로 폴백됩니다. 동일한 필드에서 타입이 매우 일관되지 않은 데이터가 아닌 한, 이는 거의 문제가 되지 않습니다.
불투명 String 저장 방식
JSONExtract 계열) 없이는 불가능하며, 이 방식은 규모가 커질수록 느려집니다.
설정, 검증 및 주의사항
설정, 검증 및 주의사항
설정검증주의할 점
- 요구 사항이 바뀌어 나중에 필드 수준 쿼리가 필요해지면, 타입이 지정된 컬럼 또는 JSON 컬럼이 있는 새 테이블을 만들고 데이터를 backfill해야 합니다. 개별 필드를 쿼리할 가능성이 조금이라도 있다면, 처음부터 하이브리드 접근 방식을 사용하는 것이 좋습니다.
JSONExtract함수는 쿼리할 때마다 문자열을 파싱합니다. 즉석 탐색에는 괜찮지만, 운영 대시보드나 높은 QPS 워크로드에는 적합하지 않습니다.- JSON payload가 크다면 String 컬럼에 압축 코덱(
ZSTD) 적용을 고려하십시오. 압축 효율이 좋습니다.
비교
Map이 더 적합한 경우
Map(String, T)이 JSON 컬럼보다 더 단순하고 효율적입니다. 대표적인 예로는 문자열 태그(Map(String, String)), 숫자 메트릭(Map(String, Float64)), 기능 플래그(Map(String, Bool))가 있습니다.
Map은 키 수준 필터링(tags['env'] = 'prod')을 지원하며, JSON보다 저장 비용이 적고 JSON 타입의 서브컬럼 오버헤드를 피할 수 있습니다. 키 조회는 기본적으로 맵을 선형 스캔한다는 점에 유의하십시오. 태그 수가 적으면 괜찮지만, 키가 100개 이상인 맵에는 with_buckets 직렬화를 고려하십시오. 값 타입이 혼합되어 있거나 구조가 중첩되어 있으면 JSON을 사용하고, 구조가 단순한 key-value 쌍이며 모든 값의 타입이 동일하면 Map을 사용하십시오.
- JSON을 적절히 사용하기 — JSON 컬럼 타입과 대안 중 언제 무엇을 사용해야 하는지 설명합니다
- JSON 데이터 타입 참고 — 타입 힌트, SKIP, max_dynamic_paths, 인트로스펙션 함수에 대한 전체 구문
- 데이터 타입 선택하기 — 일반적인 타입 선택 지침
- A New Powerful JSON Data Type for ClickHouse — JSON 타입의 저장 아키텍처를 다루는 심층 분석
- JSON 포맷 참고 — JSON 데이터용 입력/출력 포맷(JSONEachRow, JSONAsObject 등)