| Ввод | Вывод | Псевдоним |
|---|---|---|
| ✔ | ✔ |
Описание
Native — самый эффективный формат в ClickHouse, поскольку он действительно является «столбцовым»:
он не преобразует столбцы в строки.
В этом формате данные записываются и читаются блоками в бинарном формате.
Для каждого блока последовательно записываются количество строк, количество столбцов, имена и типы столбцов, а также части столбцов в блоке.
Этот формат используется в нативном интерфейсе для взаимодействия между серверами, в клиенте командной строки и в клиентах на C++.
Формат передачи данных для типов данных
При использовании нативного бинарного протокола TCP (или когда конечная точка HTTP получает
?client_protocol_version=<n>),
структура BlockInfo записывается перед количеством столбцов и строк. В примерах этого раздела используется
обычный HTTP-интерфейс без версии протокола, поэтому BlockInfo не записывается.Структура блока
number и str, из трёх строк:
Несколько блоков
Простые типы данных
RowBinary/RowBinaryWithNamesAndTypes.
Полный список типов, соответствующих этому описанию:
- (U)Int8, (U)Int16, (U)Int32, (U)Int64, (U)Int128, (U)Int256
- Float32, Float64
- Bool
- String
- FixedString(N)
- Date
- Date32
- DateTime
- DateTime64
- IPv4
- IPv6
- UUID
Сложные типы данных
RowBinary и RowBinaryWithNamesAndTypes.
- Nullable
- LowCardinality
- Array
- Map
- Variant
- Dynamic
- JSON
Nullable
Native перед самими данными для столбца с типом Nullable записывается количество байтов, равное числу строк в блоке. Каждый из этих байтов указывает, равно ли значение NULL или нет. Например, в этом запросе каждое нечётное число будет NULL:
Nullable(String) это работает аналогично. Индикатор NULL всегда задаётся байтом маски nullable —
значение маски 0x01 означает, что строка равна NULL независимо от содержимого строки. Для строк со значением NULL
базовая строка хранится как пустая строка (длина LEB128 0). Обратите внимание, что пустая строка с не-NULL
значением также имеет длину LEB128 0, поэтому эти два случая различаются только байтом маски. Например, следующий запрос:
LowCardinality
LowCardinality прозрачен, формат Native использует словарное столбцовое кодирование. Столбец кодируется как префикс версии, затем словарь уникальных значений и массив целочисленных индексов этого словаря.
Столбец можно определить как
LowCardinality(Nullable(T)), но определить его как Nullable(LowCardinality(T)) нельзя — это всегда приводит к ошибке сервера.UInt64(LE) со значением 1, который записывается один раз для каждого столбца. Затем для каждого блока записывается следующее:
UInt64(LE)— битовое полеIndexesSerializationType. Биты 0–7 кодируют ширину индекса (0 = UInt8, 1 = UInt16, 2 = UInt32, 3 = UInt64). Бит 8 (NeedGlobalDictionaryBit) никогда не устанавливается в формате Native (сервер генерирует исключение, если он встречается). Бит 9 указывает на наличие дополнительных ключей словаря. Бит 10 указывает, что словарь нужно сбросить.UInt64(LE)— количество ключей словаря, после которого сами ключи массово сериализуются с использованием кодирования внутреннего типа.UInt64(LE)— количество строк, после которого значения индексов массово сериализуются с использованием соответствующей разрядности UInt.
String, 0 для числовых типов). Для LowCardinality(Nullable(T)) индекс 0 соответствует NULL, а ключи сериализуются без обёртки Nullable.
Например, LowCardinality(String) с 5 строками ['foo', 'bar', 'baz', 'foo', 'bar']:
LowCardinality(Nullable(String)) индекс 0 — NULL:
Array
- N накопительных смещений
UInt64(little-endian, по 8 байт каждое). Строкаiсодержитoffset[i] - offset[i-1]элементов, при этомoffset[-1]неявно считается равным 0. - Все вложенные элементы из всех строк, сериализованные подряд в один непрерывный блок.
Array(UInt32) с 3 строками [[0, 10], [1, 11], [2, 12]]:
Array(String) с 4 строками [[], ['0'], ['0','1'], ['0','1','2']]:
Map
Map(K, V) кодируется как Array(Tuple(K, V)) — сначала идут смещения массива, затем все ключи, а потом все значения. Это отличается от RowBinary, где ключи и значения чередуются в каждой записи.
Например, Map(String, UInt64) с 3 строками [{'a':0,'b':10}, {'a':1,'b':11}, {'a':2,'b':12}]:
Variant
Variant кодируется следующим образом:
- Префикс режима дискриминаторов
UInt64(LE)(0= BASIC,1= COMPACT). Вывод в формате Native обычно использует BASIC (0); режим COMPACT может встречаться при чтении данных, сохраненных с включеннымuse_compact_variant_discriminators_serialization. - N дискриминаторов
UInt8, по одному на строку. - Данные каждого типа варианта в виде отдельного столбца с массовыми данными, содержащего только соответствующие строки, в порядке дискриминаторов.
Variant(String, UInt32) с 5 строками [0::UInt32, 'hello', NULL, 3::UInt32, 'hello'] (в отсортированном списке: String = 0, UInt32 = 1):
Dynamic
Dynamic как префикс структуры, за которым следует столбец Variant.
Префикс структуры содержит версию сериализации UInt64(LE), затем количество динамических типов (в формате VarUInt), а затем имена типов в виде строк. В версии V1 количество типов для совместимости записывается дважды. Следующие за ним данные представляют собой столбец Variant, список типов которого включает динамические типы и внутренний тип SharedVariant, отсортированные по алфавиту.
Например, Dynamic с 5 строками [0::UInt32, 'hello', NULL, 3::UInt32, 'hello']:
JSON
JSON в столбцовой структуре. Схема кодирования сложна и зависит от версии: она включает префикс структуры с версией сериализации, имена динамических путей и структуру общих данных, после чего следуют типизированные пути (каждый в виде отдельного столбца), динамические пути (каждый как столбец Dynamic) и общие данные для overflow-путей.
Для более простой совместимости можно использовать настройку output_format_native_write_json_as_string=1, которая сериализует JSON-столбцы как обычные текстовые строки JSON (по одному String на строку).