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
сериализуются в следующем формате: