> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-8a08bda2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Документация по формату Native

# Native

| Ввод | Вывод | Псевдоним |
| ---- | ----- | --------- |
| ✔    | ✔     |           |

<div id="description">
  ## Описание
</div>

Формат `Native` — самый эффективный формат в ClickHouse, поскольку он действительно является «столбцовым»:
он не преобразует столбцы в строки.

В этом формате данные записываются и читаются [блоками](/ru/resources/develop-contribute/introduction/architecture#block) в бинарном формате.
Для каждого блока последовательно записываются количество строк, количество столбцов, имена и типы столбцов, а также части столбцов в блоке.

Этот формат используется в нативном интерфейсе для взаимодействия между серверами, в клиенте командной строки и в клиентах на C++.

<Tip>
  Этот формат можно использовать для быстрого создания дампов, которые может читать только СУБД ClickHouse.
  Однако работать с этим форматом напрямую не всегда удобно.
</Tip>

<div id="data-types-wire-format">
  ## Формат передачи данных для типов данных
</div>

Данные передаются в столбцовом формате: каждый столбец передаётся отдельно,
а все его значения отправляются вместе как единый массив.

Каждый столбец в блоке содержит заголовок, аналогичный [RowBinaryWithNamesAndTypes](/ru/reference/formats/RowBinary/RowBinaryWithNamesAndTypes).

<Note>
  При использовании нативного бинарного протокола TCP (или когда конечная точка HTTP получает `?client_protocol_version=<n>`),
  структура `BlockInfo` записывается перед количеством столбцов и строк. В примерах этого раздела используется
  обычный HTTP-интерфейс без версии протокола, поэтому `BlockInfo` не записывается.
</Note>

<div id="block-structure">
  ### Структура блока
</div>

Следующий запрос возвращает два столбца, `number` и `str`, из трёх строк:

```bash theme={null}
curl -XPOST "http://localhost:8123?default_format=Native" --data-binary "SELECT number, toString(number) AS str FROM system.numbers LIMIT 3" > out.bin
```

Выходные данные помещаются в один блок ClickHouse и будут выглядеть так:

```js theme={null}
const data = new Uint8Array([
  // --- Заголовок блока ---
  0x02,                   // 2 столбца
  0x03,                   // 3 строки
  // -- Заголовок столбца 1 --
  0x06,                   // LEB128 - имя столбца 'number' занимает 6 байт
  0x6e, 0x75, 0x6d,       
  0x62, 0x65, 0x72,       // имя столбца: 'number'
  0x06,                   // LEB128 - тип столбца 'UInt64' занимает 6 байт
  0x55, 0x49, 0x6e,
  0x74, 0x36, 0x34,       // 'UInt64'
  0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, // 0 как UInt64
  0x01, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, // 1 как UInt64
  0x02, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, // 2 как UInt64
  0x03,                   // LEB128 - имя столбца 'str' занимает 3 байта
  0x73, 0x74, 0x72,       // имя столбца: 'str'
  0x06,                   // LEB128 - тип столбца 'String' занимает 6 байт
  0x53, 0x74, 0x72, 
  0x69, 0x6e, 0x67,       // 'String'
  0x01,                   // LEB128 - строка занимает 1 байт
  0x30,                   // '0' как String
  0x01,                   // LEB128 - строка занимает 1 байт
  0x31,                   // '1' как String
  0x01,                   // LEB128 - строка занимает 1 байт
  0x32,                   // '2' как String
])
```

<div id="multiple-blocks">
  ### Несколько блоков
</div>

Однако во многих случаях данные не помещаются в один блок, и ClickHouse отправляет их в виде нескольких блоков.
Рассмотрим следующий запрос, который извлекает две строки при уменьшенном размере блока, чтобы принудительно разбить данные так, что в каждом блоке будет по одной строке:

```bash theme={null}
curl -XPOST "http://localhost:8123?default_format=Native" --data-binary "SELECT number, toString(number) AS str                FROM system.numbers LIMIT 2                 SETTINGS max_block_size=1" \  > out.bin
```

Результат:

```js theme={null}
const data = new Uint8Array([
 
  // ----- Блок 1 ----- 
  0x02,                   // 2 столбца
  0x01,                   // 1 строка
  0x06,                   // LEB128 - имя столбца 'number' занимает 6 байт
  0x6E, 0x75, 0x6D, 
  0x62, 0x65, 0x72,       // имя столбца: 'number' 
  0x06,                   // LEB128 - тип столбца 'UInt64' занимает 6 байт
  0x55, 0x49, 0x6E, 
  0x74, 0x36, 0x34,       // 'UInt64' 
  0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, // 0 в формате UInt64
  0x03,                   // LEB128 - имя столбца 'str' занимает 3 байта
  0x73, 0x74, 0x72,       // имя столбца: 'str'
  0x06,                   // LEB128 - тип столбца 'String' занимает 6 байт
  0x53, 0x74, 0x72, 
  0x69, 0x6E, 0x67,       // 'String'
  0x01,                   // LEB128 - строка занимает 1 байт
  0x30,                   // '0' в формате String
  
  // ----- Блок 2 -----
  0x02,                   // 2 столбца
  0x01,                   // 1 строка
  0x06,                   // LEB128 - имя столбца 'number' занимает 6 байт
  0x6E, 0x75, 0x6D,  
  0x62, 0x65, 0x72,       // имя столбца: 'number'
  0x06,                   // LEB128 - тип столбца 'UInt64' занимает 6 байт
  0x55, 0x49, 0x6E,  
  0x74, 0x36, 0x34,       // 'UInt64'
  0x01, 0x00, 0x00, 0x00,  
  0x00, 0x00, 0x00, 0x00, // 1 в формате UInt64
  0x03,                   // LEB128 - имя столбца 'str' занимает 3 байта
  0x73, 0x74, 0x72,       // имя столбца: 'str'
  0x06,                   // LEB128 - тип столбца 'String' занимает 6 байт
  0x53, 0x74, 0x72,  
  0x69, 0x6E, 0x67,       // 'String'
  0x01,                   // LEB128 - строка занимает 1 байт
  0x31,                   // '1' в формате String
]);
```

<div id="simple-data-types">
  ### Простые типы данных
</div>

Формат передачи данных отдельного значения одного из простых типов данных аналогичен `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"](/ru/reference/formats/RowBinary/RowBinary#data-types-wire-format).

<div id="complex-data-types">
  ### Сложные типы данных
</div>

Кодирование следующих типов отличается от кодирования в `RowBinary` и `RowBinaryWithNamesAndTypes`.

* Nullable
* LowCardinality
* Array
* Map
* Variant
* Dynamic
* JSON

<div id="nullable">
  #### Nullable
</div>

В формате `Native` перед самими данными для столбца с типом `Nullable` записывается количество байтов, равное числу строк в блоке. Каждый из этих байтов указывает, равно ли значение `NULL` или нет. Например, в этом запросе каждое нечётное число будет `NULL`:

```bash theme={null}
curl -XPOST "http://localhost:8123?default_format=Native" \  --data-binary "SELECT if(number % 2 = 0, number, NULL) :: Nullable(UInt64) AS maybe_null                 FROM system.numbers LIMIT 5" \  > out.bin
```

Результат будет выглядеть так:

```js theme={null}
const data = new Uint8Array([
  // --- Заголовок блока ---
  0x01,                         // LEB128 - 1 столбец
  0x05,                         // LEB128 - 5 строк
  
  // -- Заголовок столбца --
  0x0A,                         // LEB128 - имя столбца занимает 10 байт
  0x6D, 0x61, 0x79, 0x62, 0x65, 
  0x5F, 0x6E, 0x75, 0x6C, 0x6C, // имя столбца: 'maybe_null'
  
  0x10,                         // LEB128 - тип столбца занимает 16 байт
  0x4E, 0x75, 0x6C, 0x6C, 
  0x61, 0x62, 0x6C, 0x65, 
  0x28, 0x55, 0x49, 0x6E, 
  0x74, 0x36, 0x34, 0x29,       // тип столбца: 'Nullable(UInt64)'
  
  // -- Маска Nullable --
  0x00,                         // Строка 0 — NOT NULL
  0x01,                         // Строка 1 — NULL
  0x00,                         // Строка 2 — NOT NULL
  0x01,                         // Строка 3 — NULL
  0x00,                         // Строка 4 — NOT NULL
  
  // -- Значения UInt64 --
  0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00,       // Строка 0: 0 как UInt64

  // даже если в блоке хранится корректное значение для этого числа,
  // пользователю оно всё равно должно быть возвращено как NULL!
  0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,       // Строка #1: NULL
  
  0x02, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,       // Строка #2: 2 как UInt64
  
  0x03, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00,       // Строка #3: NULL, аналогично строке #1
  
  0x04, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00,       // Строка #4: 4 как UInt64
]);
```

С `Nullable(String)` это работает аналогично. Индикатор `NULL` всегда задаётся байтом маски nullable —
значение маски `0x01` означает, что строка равна `NULL` независимо от содержимого строки. Для строк со значением `NULL`
базовая строка хранится как пустая строка (длина LEB128 `0`). Обратите внимание, что пустая строка с не-`NULL`
значением также имеет длину LEB128 `0`, поэтому эти два случая различаются только байтом маски. Например, следующий запрос:

```bash theme={null}
curl -XPOST "http://localhost:8123?default_format=Native" \  --data-binary "SELECT if(number % 2 = 0, toString(number), NULL) :: Nullable(String) AS maybe_str                 FROM system.numbers LIMIT 5" \  > out.bin
```

Результат будет выглядеть так:

```js theme={null}
const data = new Uint8Array([
  // --- Заголовок блока ---
  0x01, // LEB128 - 1 столбец
  0x05, // LEB128 - 5 строк

  // -- Заголовок столбца --
  0x09, // LEB128 - имя столбца занимает 9 байт
  0x6d,
  0x61,
  0x79,
  0x62,
  0x65,
  0x5f,
  0x73,
  0x74,
  0x72, // имя столбца: 'maybe_str'

  0x10, // LEB128 - тип столбца занимает 16 байт
  0x4e,
  0x75,
  0x6c,
  0x6c,
  0x61,
  0x62,
  0x6c,
  0x65,
  0x28,
  0x53,
  0x74,
  0x72,
  0x69,
  0x6e,
  0x67,
  0x29, // тип столбца: 'Nullable(String)'

  // -- Маска Nullable --
  0x00, // Строка 0 — NOT NULL
  0x01, // Строка 1 — NULL
  0x00, // Строка 2 — NOT NULL
  0x01, // Строка 3 — NULL
  0x00, // Строка 4 — NOT NULL

  // -- Строковые значения --
  0x01,
  0x30, // Строка 0: LEB128 == 1, '0' как String
  0x00, // Строка 1: LEB128 == 0, NULL
  0x01,
  0x32, // Строка 2: LEB128 == 1, '2' как String
  0x00, // Строка 3: LEB128 == 0, NULL
  0x01,
  0x34, // Строка 4: LEB128 == 1, '4' как String
])
```

<div id="lowcardinality">
  #### LowCardinality
</div>

В отличие от [RowBinary](/ru/reference/formats/RowBinary/RowBinary#lowcardinality), где `LowCardinality` прозрачен, формат Native использует словарное столбцовое кодирование. Столбец кодируется как префикс версии, затем словарь уникальных значений и массив целочисленных индексов этого словаря.

<Note>
  Столбец можно определить как `LowCardinality(Nullable(T))`, но определить его как `Nullable(LowCardinality(T))` нельзя — это всегда приводит к ошибке сервера.
</Note>

Префикс версии — это `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.

Словарь всегда содержит значение по умолчанию по индексу 0 (например, пустую строку для `String`, 0 для числовых типов). Для `LowCardinality(Nullable(T))` индекс 0 соответствует `NULL`, а ключи сериализуются без обёртки `Nullable`.

Например, `LowCardinality(String)` с 5 строками `['foo', 'bar', 'baz', 'foo', 'bar']`:

```text theme={null}
// Префикс версии
01 00 00 00 00 00 00 00    // UInt64(LE) = 1

// IndexesSerializationType: индексы UInt8, есть ключи, обновить словарь
00 06 00 00 00 00 00 00    // UInt64(LE) = 0x0600

04 00 00 00 00 00 00 00    // 4 ключа словаря
00                          // ключ 0: "" (по умолчанию)
03 66 6f 6f                 // ключ 1: "foo"
03 62 61 72                 // ключ 2: "bar"
03 62 61 7a                 // ключ 3: "baz"

05 00 00 00 00 00 00 00    // 5 строк
01 02 03 01 02              // индексы → "foo", "bar", "baz", "foo", "bar"
```

В `LowCardinality(Nullable(String))` индекс 0 — `NULL`:

```text theme={null}
01 00 00 00 00 00 00 00    // версия
00 06 00 00 00 00 00 00    // IndexesSerializationType
03 00 00 00 00 00 00 00    // 3 ключа
00                          // ключ 0: NULL
00                          // ключ 1: "" (по умолчанию)
03 79 65 73                 // ключ 2: "yes"
05 00 00 00 00 00 00 00    // 5 строк
02 00 02 00 02              // индексы → "yes", NULL, "yes", NULL, "yes"
```

<div id="array">
  #### Array
</div>

В отличие от [RowBinary](/ru/reference/formats/RowBinary/RowBinary#array), где каждому массиву предшествует число элементов в кодировке LEB128, формат Native кодирует массивы как два столбцовых подпотока:

* N накопительных смещений `UInt64` (little-endian, по 8 байт каждое). Строка `i` содержит `offset[i] - offset[i-1]` элементов, при этом `offset[-1]` неявно считается равным 0.
* Все вложенные элементы из всех строк, сериализованные подряд в один непрерывный блок.

Например, `Array(UInt32)` с 3 строками `[[0, 10], [1, 11], [2, 12]]`:

```text theme={null}
// Смещения
02 00 00 00 00 00 00 00    // 2 (строка 0: 2 элемента)
04 00 00 00 00 00 00 00    // 4 (строка 1: 2 элемента)
06 00 00 00 00 00 00 00    // 6 (строка 2: 2 элемента)

// Вложенные значения UInt32 (всего 6)
00 00 00 00                 // 0
0a 00 00 00                 // 10
01 00 00 00                 // 1
0b 00 00 00                 // 11
02 00 00 00                 // 2
0c 00 00 00                 // 12
```

Пустой массив имеет то же смещение, что и в предыдущей строке. Например, `Array(String)` с 4 строками `[[], ['0'], ['0','1'], ['0','1','2']]`:

```text theme={null}
00 00 00 00 00 00 00 00    // 0 (empty)
01 00 00 00 00 00 00 00    // 1
03 00 00 00 00 00 00 00    // 3
06 00 00 00 00 00 00 00    // 6
01 30                       // "0"
01 30                       // "0"
01 31                       // "1"
01 30                       // "0"
01 31                       // "1"
01 32                       // "2"
```

<div id="map">
  #### Map
</div>

`Map(K, V)` кодируется как `Array(Tuple(K, V))` — сначала идут смещения массива, затем все ключи, а потом все значения. Это отличается от [RowBinary](/ru/reference/formats/RowBinary/RowBinary#map), где ключи и значения чередуются в каждой записи.

Например, `Map(String, UInt64)` с 3 строками `[{'a':0,'b':10}, {'a':1,'b':11}, {'a':2,'b':12}]`:

```text theme={null}
// Смещения массива
02 00 00 00 00 00 00 00    // 2
04 00 00 00 00 00 00 00    // 4
06 00 00 00 00 00 00 00    // 6

// Все ключи (6 строк)
01 61                       // "a"
01 62                       // "b"
01 61                       // "a"
01 62                       // "b"
01 61                       // "a"
01 62                       // "b"

// Все значения (6 UInt64)
00 00 00 00 00 00 00 00    // 0
0a 00 00 00 00 00 00 00    // 10
01 00 00 00 00 00 00 00    // 1
0b 00 00 00 00 00 00 00    // 11
02 00 00 00 00 00 00 00    // 2
0c 00 00 00 00 00 00 00    // 12
```

<div id="variant">
  #### Variant
</div>

В отличие от [RowBinary](/ru/reference/formats/RowBinary/RowBinary#variant), где каждая строка содержит собственный байт дискриминатора, за которым сразу следует встроенное значение, формат Native отделяет дискриминаторы от данных.

<Warning>
  Как и в RowBinary, типы в определении всегда сортируются по алфавиту, а дискриминатор — это индекс в этом отсортированном списке. `0xFF` (255) обозначает `NULL`.
</Warning>

Столбец `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):

```text theme={null}
00 00 00 00 00 00 00 00    // режим дискриминаторов = BASIC
01 00 ff 01 00              // UInt32, String, NULL, UInt32, String

// String (2 значения, строки 1 и 4)
05 68 65 6c 6c 6f          // "hello"
05 68 65 6c 6c 6f          // "hello"

// UInt32 (2 значения, строки 0 и 3)
00 00 00 00                 // 0
03 00 00 00                 // 3
```

<div id="dynamic">
  #### Dynamic
</div>

В отличие от [RowBinary](/ru/reference/formats/RowBinary/RowBinary#dynamic), где каждое значение является самоописывающимся (префикс типа + значение), формат Native сериализует `Dynamic` как префикс структуры, за которым следует столбец [Variant](#variant).

Префикс структуры содержит версию сериализации `UInt64(LE)`, затем количество динамических типов (в формате VarUInt), а затем имена типов в виде строк. В версии V1 количество типов для совместимости записывается дважды. Следующие за ним данные представляют собой столбец `Variant`, список типов которого включает динамические типы и внутренний тип `SharedVariant`, отсортированные по алфавиту.

Например, `Dynamic` с 5 строками `[0::UInt32, 'hello', NULL, 3::UInt32, 'hello']`:

```text theme={null}
// Префикс структуры (V1)
01 00 00 00 00 00 00 00    // версия = V1
02                          // кол-во типов (V1 записывает дважды)
02                          // кол-во типов
06 53 74 72 69 6e 67       // "String"
06 55 49 6e 74 33 32       // "UInt32"

// Данные Variant: Variant(SharedVariant, String, UInt32)
// дискриминанты: SharedVariant=0, String=1, UInt32=2
00 00 00 00 00 00 00 00    // режим дискриминаторов = BASIC
02 01 ff 02 01              // UInt32, String, NULL, UInt32, String
// SharedVariant: 0 значений
05 68 65 6c 6c 6f          // String: "hello"
05 68 65 6c 6c 6f          // String: "hello"
00 00 00 00                 // UInt32: 0
03 00 00 00                 // UInt32: 3
```

<div id="json">
  #### JSON
</div>

В отличие от [RowBinary](/ru/reference/formats/RowBinary/RowBinary#json), где каждая строка содержит имена путей и значения и потому является самоописывающейся, формат Native сериализует `JSON` в столбцовой структуре. Схема кодирования сложна и зависит от версии: она включает префикс структуры с версией сериализации, имена динамических путей и структуру общих данных, после чего следуют типизированные пути (каждый в виде отдельного столбца), динамические пути (каждый как столбец [Dynamic](#dynamic)) и общие данные для overflow-путей.

Для более простой совместимости можно использовать настройку `output_format_native_write_json_as_string=1`, которая сериализует JSON-столбцы как обычные текстовые строки JSON (по одному `String` на строку).
