| 입력 | 출력 | 별칭 |
|---|---|---|
| ✔ | ✔ |
설명
Native 형식은 컬럼을 행으로 변환하지 않는 진정한 “열 지향” 포맷이므로 ClickHouse에서 가장 효율적인 포맷입니다.
이 포맷에서는 데이터가 바이너리 형식으로 블록 단위로 기록되고 읽힙니다.
각 블록에는 행 수, 컬럼 수, 컬럼 이름과 타입, 그리고 블록 내 각 컬럼 데이터의 일부가 차례대로 기록됩니다.
이 포맷은 서버 간 상호작용을 위한 네이티브 인터페이스, command-line client 사용, 그리고 C++ 클라이언트에서 사용됩니다.
데이터 타입 wire 형식
네이티브 TCP 바이너리 프로토콜을 사용하거나(또는 HTTP 엔드포인트가
?client_protocol_version=<n>을 받을 때),
컬럼 수와 행 수 앞에 BlockInfo 구조체가 기록됩니다. 이 섹션의 예시는
프로토콜 버전이 없는 일반 HTTP 인터페이스를 사용하므로 BlockInfo는 생략됩니다.블록 구조
number와 str 두 개의 컬럼과 3개의 행을 반환합니다:
여러 블록
단순 데이터 타입
RowBinary/RowBinaryWithNamesAndTypes와 유사합니다.
이에 해당하는 전체 타입 목록은 다음과 같습니다.
- (U)Int8, (U)Int16, (U)Int32, (U)Int64, (U)Int128, (U)Int256
- Float32, Float64
- Bool
- String
- FixedString(N)
- Date
- Date32
- DateTime
- DateTime64
- IPv4
- IPv6
- UUID
복합 데이터 타입
RowBinary 및 RowBinaryWithNamesAndTypes와 다릅니다.
- 널 허용
- LowCardinality
- 배열
- 맵
- Variant
- Dynamic
- JSON
널 허용
Native 형식에서는 널 허용 컬럼의 실제 데이터 앞에 블록의 행 수와 동일한 바이트 수가 옵니다. 각 바이트는 해당 값이 NULL인지 여부를 나타냅니다. 예를 들어, 다음 쿼리에서는 각 홀수가 NULL이 됩니다:
Nullable(String)도 비슷한 방식으로 작동합니다. null 표시자는 항상 널 허용 마스크 바이트에서 오며 —
마스크 값이 0x01이면 문자열 내용과 관계없이 해당 행은 NULL입니다. NULL 행의 경우,
내부 문자열은 빈 문자열(LEB128 길이 0)로 저장됩니다. 비-NULL 빈
문자열 역시 LEB128 길이가 0이므로, 두 경우를 구분하는 것은 마스크 바이트뿐입니다. 예를 들어, 다음 쿼리:
LowCardinality
LowCardinality가 투명하게 처리되는 RowBinary와 달리, Native 형식은 딕셔너리 기반의 열 지향 인코딩을 사용합니다. 컬럼은 버전 접두사로 시작하고, 이어서 고유 값 딕셔너리와 해당 딕셔너리를 참조하는 정수 인덱스 배열로 인코딩됩니다.
컬럼은
LowCardinality(Nullable(T))로 정의할 수 있지만, Nullable(LowCardinality(T))로 정의할 수는 없습니다 — 이렇게 정의하면 항상 서버에서 오류가 발생합니다.1인 UInt64(LE)이며, 컬럼마다 한 번만 기록됩니다. 그다음 각 블록마다 다음이 기록됩니다.
UInt64(LE)—IndexesSerializationType비트 필드입니다. 비트 0–7은 인덱스 너비를 인코딩합니다(0 = UInt8, 1 = UInt16, 2 = UInt32, 3 = UInt64). 비트 8(NeedGlobalDictionaryBit)은 Native 형식에서는 절대 설정되지 않습니다(이 값이 나타나면 서버가 예외를 발생시킵니다). 비트 9는 추가 딕셔너리 키가 있음을 나타냅니다. 비트 10은 딕셔너리를 재설정해야 함을 나타냅니다.UInt64(LE)— 딕셔너리 키 수이며, 뒤이어 내부 타입 인코딩을 사용해 키가 일괄 직렬화되어 기록됩니다.UInt64(LE)— 행 수이며, 뒤이어 적절한 UInt 너비를 사용해 인덱스 값이 일괄 직렬화되어 기록됩니다.
String의 경우 빈 문자열, 숫자 타입의 경우 0). LowCardinality(Nullable(T))에서는 인덱스 0이 NULL을 나타내며, 키는 Nullable 래퍼 없이 직렬화됩니다.
예를 들어, 5개 행 ['foo', 'bar', 'baz', 'foo', 'bar']를 가지는 LowCardinality(String)은 다음과 같습니다:
LowCardinality(Nullable(String))에서는 인덱스 0은 NULL입니다:
배열
- 누적
UInt64오프셋 N개(리틀 엔디언, 각각 8바이트).i번째 행에는offset[i] - offset[i-1]개의 요소가 있으며,offset[-1]은 암묵적으로 0입니다. - 모든 행의 중첩 요소를 하나로 이어서 연속적으로 일괄 직렬화합니다.
[[0, 10], [1, 11], [2, 12]]를 가진 Array(UInt32)는 다음과 같습니다:
Array(String) 값이 [[], ['0'], ['0','1'], ['0','1','2']]인 경우는 다음과 같습니다:
맵
Map(K, V)는 Array(Tuple(K, V))로 인코딩됩니다. 즉, 배열 오프셋 다음에 모든 키가 나오고, 그 뒤에 모든 값이 나옵니다. 이는 각 항목마다 키와 값이 번갈아 저장되는 RowBinary와 다릅니다.
예시로, 3개의 행이 있는 Map(String, UInt64) [{'a':0,'b':10}, {'a':1,'b':11}, {'a':2,'b':12}]는 다음과 같습니다:
Variant
Variant 컬럼은 다음과 같이 인코딩됩니다.
UInt64(LE)판별자 모드 접두사 (0= BASIC,1= COMPACT). Native 형식 출력은 일반적으로 BASIC (0)을 사용하며, COMPACT 모드는use_compact_variant_discriminators_serialization이 활성화된 상태로 저장된 데이터를 읽을 때 나타날 수 있습니다.- 각 행마다 하나씩, N개의
UInt8판별자. - 각 variant type의 데이터는 판별자 순서대로, 해당하는 행만 포함하는 별도의 대량 컬럼으로 인코딩됩니다.
Variant(String, UInt32)에 5개의 행 [0::UInt32, 'hello', NULL, 3::UInt32, 'hello']가 있는 경우(정렬 결과: String = 0, UInt32 = 1):
Dynamic
Dynamic을 구조체 접두사 다음에 Variant 컬럼이 이어지는 형태로 직렬화합니다.
구조체 접두사에는 UInt64(LE) 직렬화 버전, 동적 타입의 개수(VarUInt), 그리고 문자열 형태의 타입 이름이 포함됩니다. V1 버전에서는 호환성을 위해 타입 개수를 두 번 기록합니다. 그 뒤에 오는 데이터는 동적 타입과 내부 SharedVariant 타입을 합친 뒤 알파벳순으로 정렬한 타입 목록을 가지는 Variant 컬럼입니다.
예를 들어, 5개의 행 [0::UInt32, 'hello', NULL, 3::UInt32, 'hello']이 있는 Dynamic은 다음과 같습니다:
JSON
JSON을 열 지향 구조로 직렬화합니다. 인코딩은 복잡하고 버전에 따라 달라집니다. 즉, 직렬화 버전, 동적 경로 이름, shared data 레이아웃을 포함하는 구조체 접두사로 구성되며, 그 뒤에 타입이 지정된 경로(각각 벌크 컬럼), 동적 경로(각각 Dynamic 컬럼), 그리고 오버플로우 경로용 shared data가 이어집니다.
더 간단한 상호 운용성을 위해 output_format_native_write_json_as_string=1 설정 사용을 고려하십시오. 이 설정은 JSON 컬럼을 일반 JSON 텍스트 문자열(각 행당 String 1개)로 직렬화합니다.)