Dynamic
Этот тип позволяет хранить значения любого типа внутри него без предварительного знания всех типов.
Чтобы объявить колонку типа Dynamic
, используйте следующий синтаксис:
Где N
— это необязательный параметр от 0
до 254
, указывающий, сколько различных типов данных может храниться в виде отдельных подколонок внутри колонки типа Dynamic
в пределах одного блока данных, который хранится отдельно (например, в пределах одной части данных для таблицы MergeTree). Если этот лимит превышен, все значения с новыми типами будут храниться вместе в специальной общей структуре данных в двоичном формате. Значение по умолчанию для max_types
равно 32
.
Создание Dynamic
Используя тип Dynamic
в определении колонки таблицы:
Используя CAST из обычной колонки:
Используя CAST из колонки Variant
:
Чтение вложенных типов Dynamic как подколонок
Тип Dynamic
поддерживает чтение одного вложенного типа из колонки Dynamic
, используя имя типа в качестве подколонки. Итак, если у вас есть колонка d Dynamic
, вы можете читать подколонку любого допустимого типа T
, используя синтаксис d.T
, эта подколонка будет иметь тип Nullable(T)
, если T
может находиться внутри Nullable
, и T
в противном случае. Эта подколонка будет иметь такой же размер, как и оригинальная колонка Dynamic
, и будет содержать значения NULL
(или пустые значения, если T
не может находиться внутри Nullable
) во всех строках, где оригинальная колонка Dynamic
не имеет типа T
.
Подколонки Dynamic
также могут быть прочитаны с помощью функции dynamicElement(dynamic_column, type_name)
.
Примеры:
Чтобы узнать, какой вариант хранится в каждой строке, можно использовать функцию dynamicType(dynamic_column)
. Она возвращает String
со значением имени типа для каждой строки (или 'None'
, если строка равна NULL
).
Пример:
Конверсия между колонкой Dynamic и другими колонками
Существует 4 возможные конверсии, которые можно выполнить с колонкой Dynamic
.
Преобразование обычной колонки в колонку Dynamic
Преобразование колонки String в колонку Dynamic через парсинг
Для парсинга значений типа Dynamic
из колонки String
вы можете включить настройку cast_string_to_dynamic_use_inference
:
Преобразование колонки Dynamic в обычную колонку
Возможно преобразование колонки Dynamic
в обычную колонку. В этом случае все вложенные типы будут преобразованы в целевой тип:
Преобразование колонки Variant в колонку Dynamic
Преобразование колонки Dynamic(max_types=N) в другую колонку Dynamic(max_types=K)
Если K >= N
, то при преобразовании данные не меняются:
Если K < N
, значения с самыми редкими типами будут вставлены в одну специальную подколонку, но все равно будут доступны:
Функция isDynamicElementInSharedData
возвращает true
для строк, которые хранятся в специальной общей структуре данных внутри Dynamic
, и как мы видим, результирующая колонка содержит только 2 типа, которые не хранятся в общей структуре данных.
Если K=0
, все типы будут вставлены в одну специальную подколонку:
Чтение типа Dynamic из данных
Все текстовые форматы (TSV, CSV, CustomSeparated, Values, JSONEachRow и др.) поддерживают чтение типа Dynamic
. При парсинге данных ClickHouse пытается вывести тип каждого значения и использовать его при вставке в колонку Dynamic
.
Пример:
Использование типа Dynamic в функциях
Большинство функций поддерживают аргументы с типом Dynamic
. В этом случае функция выполняется отдельно для каждого внутреннего типа данных, хранящегося в колонке Dynamic
. Когда тип результата функции зависит от типов аргументов, результат такой функции, выполненной с аргументами Dynamic
, будет Dynamic
. Когда тип результата функции не зависит от типов аргументов — результат будет Nullable(T)
, где T
— обычный тип результата этой функции.
Примеры:
Если функцию нельзя выполнить для некоторых типов внутри колонки Dynamic
, будет выброшено исключение:
Мы можем отфильтровать ненужные типы:
Или извлечь требуемый тип как подколонку:
Использование типа Dynamic в ORDER BY и GROUP BY
При использовании ORDER BY
и GROUP BY
значения типов Dynamic
сравниваются так же, как значения типа Variant
:
Результат оператора <
для значений d1
с подлежащим типом T1
и d2
с подлежащим типом T2
типа Dynamic
определяется следующим образом:
- Если
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
Достижение предела количества различных типов данных, хранящихся внутри Dynamic
Тип данных Dynamic
может хранить лишь ограниченное количество различных типов данных как отдельные подколонки. По умолчанию этот лимит составляет 32, но вы можете изменить его в объявлении типа с помощью синтаксиса Dynamic(max_types=N)
, где N находится в пределах от 0 до 254 (из-за особенностей реализации невозможно иметь более 254 различных типов данных, которые могут храниться как отдельные подколонки внутри Dynamic). Когда лимит достигается, все новые типы данных, вставленные в колонку Dynamic
, будут вставлены в единую общую структуру данных, которая хранит значения с различными типами данных в двоичном формате.
Давайте посмотрим, что происходит, когда лимит достигается в различных сценариях.
Достижение лимита во время парсинга данных
Во время парсинга значений Dynamic
из данных, когда лимит достигается для текущего блока данных, все новые значения будут вставлены в общую структуру данных:
Как мы видим, после вставки 3 различных типов Int64
, Array(Int64)
и String
все новые типы были вставлены в специальную общую структуру данных.
Во время слияния частей данных в движках таблиц MergeTree
Во время слияния нескольких частей данных в таблице MergeTree колонка Dynamic
в результирующей части данных может достичь лимита различных типов данных, которые могут храниться в отдельных подколонках, и не сможет хранить все типы как подколонки из исходных частей. В этом случае ClickHouse выбирает, какие типы останутся как отдельные подколонки после слияния, и какие типы будут вставлены в общую структуру данных. В большинстве случаев ClickHouse пытается сохранить наиболее частые типы и хранить самые редкие типы в общей структуре данных, но это зависит от реализации.
Давайте посмотрим на пример такого слияния. Сначала создадим таблицу с колонкой Dynamic
, установим лимит различных типов данных на 3
и вставим значения с 5
различными типами:
Каждая вставка создаст отдельную часть данных с колонкой Dynamic
, содержащей единственный тип:
Теперь давайте объединим все части в одну и посмотрим, что произойдет:
Как мы видим, ClickHouse сохранил наиболее частые типы UInt64
и Array(UInt64)
в качестве подколонок и вставил все остальные типы в общую структуру данных.
Функции JSONExtract с Dynamic
Все функции JSONExtract*
поддерживают тип Dynamic
:
Бинарный формат вывода
В формате RowBinary значения типа Dynamic
сериализуются в следующем формате: