Перейти к основному содержимому
Перейти к основному содержимому

Dynamic

Этот тип позволяет хранить значения любого типа внутри него, не зная всех этих типов заранее.

Чтобы объявить столбец типа Dynamic, используйте следующий синтаксис:

Где N — это необязательный параметр от 0 до 254, указывающий, сколько различных типов данных может быть сохранено как отдельные подстолбцы внутри столбца типа Dynamic в одном блоке данных, который хранится отдельно (например, в одной части данных для таблицы MergeTree). Если этот лимит превышен, все значения с новыми типами будут храниться вместе в специальной общей структуре данных в бинарной форме. Значение по умолчанию для max_types32.

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