Dynamic 타입 컬럼을 선언하려면 다음 구문을 사용하십시오:
N은 0부터 254 사이의 선택적 매개변수로, 별도로 저장되는 단일 데이터 블록(예를 들어 MergeTree 테이블의 단일 데이터 파트(data part)) 전체에서 Dynamic 타입 컬럼 안에 서로 다른 데이터 타입을 별도의 서브컬럼으로 몇 개까지 저장할 수 있는지를 나타냅니다. 이 한도를 초과하면 새 타입의 모든 값은 특수한 공유 데이터 구조(shared data structure)에 바이너리 형식으로 함께 저장됩니다. max_types의 기본값은 32입니다.
Dynamic 생성
Dynamic 유형을 사용합니다:
Variant 컬럼에서 CAST 사용하기:
Dynamic 중첩 타입을 서브컬럼으로 읽기
Dynamic 타입은 타입 이름을 서브컬럼으로 사용해 Dynamic 컬럼에서 단일 중첩 타입을 읽을 수 있도록 지원합니다.
따라서 d Dynamic 컬럼이 있으면 d.T 구문을 사용해 임의의 유효한 타입 T의 서브컬럼을 읽을 수 있습니다.
이 서브컬럼의 타입은 T가 Nullable 안에 포함될 수 있으면 Nullable(T)이고, 그렇지 않으면 T입니다. 또한 이 서브컬럼은
원본 Dynamic 컬럼과 크기가 같으며, 원본 Dynamic 컬럼의 타입이 T가 아닌 모든 행에는 NULL 값(또는 T가 Nullable 안에 포함될 수 없는 경우 빈 값)이 들어 있습니다.
Dynamic 서브컬럼은 dynamicElement(dynamic_column, type_name) 함수를 사용해서도 읽을 수 있습니다.
예시:
dynamicType(dynamic_column) 함수를 사용할 수 있습니다. 이 함수는 각 행에 대해 값의 type name이 담긴 String을 반환합니다(행이 NULL이면 'None'을 반환).
예시:
Dynamic 컬럼과 다른 컬럼 간의 변환
Dynamic 컬럼으로 수행할 수 있는 변환은 4가지입니다.
일반 컬럼을 Dynamic 컬럼으로 변환
파싱을 통해 String 컬럼을 Dynamic 컬럼으로 변환하기
String 컬럼에서 Dynamic 타입 값을 파싱하려면 cast_string_to_dynamic_use_inference 설정을 활성화할 수 있습니다:
Dynamic 컬럼을 일반 컬럼으로 변환하기
Dynamic 컬럼은 일반 컬럼으로 변환할 수 있습니다. 이 경우 모든 중첩 타입이 대상 타입으로 변환됩니다:
Variant 컬럼을 Dynamic 컬럼으로 변환
Dynamic(max_types=N) 컬럼을 다른 Dynamic(max_types=K)으로 변환하기
K >= N이면 변환 과정에서 데이터는 변경되지 않습니다:
K < N이면 가장 드문 타입의 값들은 하나의 특수 서브컬럼에 삽입되지만, 여전히 접근할 수 있습니다:
isDynamicElementInSharedData는 Dynamic 내부의 특수한 공유 데이터 구조에 저장된 행에 대해 true를 반환하며, 알 수 있듯이 결과 컬럼에는 공유 데이터 구조에 저장되지 않는 2개의 타입만 포함됩니다.
K=0이면 모든 타입이 하나의 특수한 서브컬럼에 삽입됩니다:
데이터에서 Dynamic 타입 읽기
Dynamic 타입 읽기를 지원합니다. 데이터를 파싱하는 동안 ClickHouse는 각 값의 유형을 추론한 뒤, Dynamic 컬럼에 삽입할 때 해당 유형을 사용하려고 시도합니다.
예시:
함수에서 Dynamic 타입 사용
Dynamic 타입의 인수를 지원합니다. 이 경우 함수는 Dynamic 컬럼 내부에 저장된 각 내부 데이터 타입별로 개별 실행됩니다.
함수의 결과 타입이 인수 타입에 따라 달라지는 경우, Dynamic 인수로 실행된 함수의 결과 타입은 Dynamic이 됩니다. 함수의 결과 타입이 인수 타입에 의존하지 않는 경우, 결과는 Nullable(T)가 되며, 여기서 T는 해당 함수의 일반적인 결과 타입입니다.
예시:
Dynamic 컬럼 내의 일부 유형에서 함수를 실행할 수 없으면 예외가 발생합니다:
유형 불일치 시 동작
dynamic_throw_on_type_mismatch는 함수가 Dynamic 컬럼에 적용될 때 각 행에 실제로 저장된 유형이 해당 함수와 호환되지 않으면 어떻게 처리할지를 제어합니다.
true(기본값) — 처음으로 호환되지 않는 행에서 예외(ILLEGAL_TYPE_OF_ARGUMENT)를 발생시킵니다.false— 호환되지 않는 행에는NULL을 반환하고, 호환되는 행의 결과는 그대로 유지합니다.
ORDER BY 및 GROUP BY에서 Dynamic 타입 사용
ORDER BY 및 GROUP BY에서 Dynamic 타입의 값은 Variant 타입의 값과 비슷한 방식으로 비교됩니다.
Dynamic 타입에서 내부 타입이 T1인 값 d1과 내부 타입이 T2인 값 d2에 대한 < 연산자의 결과는 다음과 같이 정의됩니다:
T1 = T2 = T이면 결과는d1.T < d2.T입니다(내부 값이 비교됩니다).T1 != T2이면 결과는T1 < T2입니다(타입 이름이 비교됩니다).
Dynamic 타입은 GROUP BY/ORDER BY 키에 사용할 수 없습니다. 사용하려면 이 타입의 특수한 비교 규칙을 고려하고 allow_suspicious_types_in_group_by/allow_suspicious_types_in_order_by 설정을 활성화하십시오.
예시:
Dynamic type 함수의 특수한 동작 때문에 </>/= 등의 비교 함수를 실행할 때는 적용되지 않습니다
Dynamic 내부에 저장되는 서로 다른 데이터 타입 수 한도에 도달한 경우
Dynamic 데이터 타입은 제한된 수의 서로 다른 데이터 타입만 별도의 서브컬럼으로 저장할 수 있습니다. 기본 한도는 32이지만, 타입 선언에서 Dynamic(max_types=N) 구문을 사용해 변경할 수 있습니다. 여기서 N은 0에서 254 사이의 값입니다(구현 세부 사항 때문에 Dynamic 내부에서 별도의 서브컬럼으로 저장할 수 있는 서로 다른 데이터 타입은 254개를 초과할 수 없습니다).
이 한도에 도달하면 이후 Dynamic 컬럼에 삽입되는 모든 새로운 데이터 타입은, 서로 다른 데이터 타입의 값을 바이너리 형식으로 저장하는 하나의 공유 데이터 구조에 삽입됩니다.
이제 서로 다른 시나리오에서 이 한도에 도달하면 어떤 일이 발생하는지 살펴보겠습니다.
데이터 파싱 중 한도에 도달한 경우
Dynamic 값을 파싱하는 동안 현재 데이터 블록에서 한도에 도달하면, 모든 새 값이 공유 데이터 구조에 삽입됩니다:
Int64, Array(Int64), String을 삽입한 후 새 타입은 모두 특수한 공유 데이터 구조에 저장되었습니다.
MergeTree 테이블 엔진에서 데이터 파트가 머지되는 동안
Dynamic 컬럼은 내부의 별도 서브컬럼에 저장할 수 있는 서로 다른 데이터 타입 수의 한도에 도달할 수 있으며, 그 결과 원본 파트의 모든 타입을 서브컬럼으로 저장하지 못할 수 있습니다.
이 경우 ClickHouse는 머지 후 어떤 타입을 별도 서브컬럼으로 유지하고 어떤 타입을 공유 데이터 구조에 삽입할지 선택합니다. 대부분의 경우 ClickHouse는 가장 자주 나타나는 타입을 유지하고, 가장 드물게 나타나는 타입은 공유 데이터 구조에 저장하려고 하지만, 이는 구현에 따라 달라집니다.
이러한 머지의 예시를 살펴보겠습니다. 먼저 Dynamic 컬럼이 있는 테이블을 만들고, 서로 다른 데이터 타입 수의 한도를 3으로 설정한 다음, 서로 다른 5개의 타입 값을 삽입하겠습니다:
Dynamic 컬럼을 가진 별도의 데이터 파트가 생성됩니다:
UInt64와 Array(UInt64)는 서브컬럼으로 유지하고, 나머지 모든 타입은 공유 데이터에 삽입했습니다.
Dynamic와 함께 사용하는 JSONExtract 함수
JSONExtract* 함수는 Dynamic 타입을 지원합니다:
바이너리 출력 형식
Dynamic 타입 값은 다음과 같은 형식으로 직렬화됩니다: