Динамический
Этот тип позволяет хранить значения любого типа внутри себя без необходимости заранее знать все из них.
Чтобы объявить колонку типа Dynamic
, используйте следующий синтаксис:
Где N
- это необязательный параметр от 0
до 254
, указывающий, сколько различных типов данных может храниться в виде отдельных подколонок внутри колонки типа Dynamic
в пределах одного блока данных, который хранится отдельно (например, в пределах одной части данных для таблицы MergeTree). Если этот лимит превышен, все значения с новыми типами будут храниться вместе в специальной общей структуре данных в двоичном формате. Значение по умолчанию для max_types
равно 32
.
Тип данных Dynamic - это бета-функция. Чтобы использовать его, установите enable_dynamic_type = 1
.
Создание Динамического
Использование типа 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
сериализуются в следующем формате: