| Entrada | Saída | Alias |
|---|---|---|
| ✔ | ✔ |
Descrição
Native é o formato mais eficiente do ClickHouse porque é de fato “colunar”,
ou seja, não converte colunas em linhas.
Nesse formato, os dados são gravados e lidos em blocos, em formato binário.
Para cada bloco, são registrados, um após o outro, o número de linhas, o número de colunas, os nomes e tipos das colunas e as partes das colunas no bloco.
Esse é o formato usado na interface nativa para a interação entre servidores, no cliente de linha de comando e em clientes C++.
Formato wire dos tipos de dados
Ao usar o protocolo binário TCP nativo (ou quando o endpoint HTTP recebe
?client_protocol_version=<n>),
uma estrutura BlockInfo é gravada antes das contagens de colunas e linhas. Os exemplos nesta seção usam
a interface HTTP simples, sem versão de protocolo, o que omite BlockInfo.Estrutura do bloco
number e str, com três linhas:
Múltiplos blocos
Tipos de dados simples
RowBinary/RowBinaryWithNamesAndTypes.
A lista completa de tipos que correspondem a essa descrição inclui:
- (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
Tipos de dados complexos
RowBinary e RowBinaryWithNamesAndTypes.
- Nullable
- LowCardinality
- Array
- Map
- Variant
- Dynamic
- JSON
Nullable
Native, uma coluna Nullable terá uma quantidade de bytes igual ao número de linhas no bloco antes dos dados propriamente ditos. Cada um desses bytes indica se o valor é NULL ou não. Por exemplo, com esta consulta, cada número ímpar será NULL:
Nullable(String). O indicador de nulo sempre vem do byte da máscara de nulabilidade —
um valor de máscara 0x01 significa que a linha é NULL, independentemente do conteúdo da string. Para linhas NULL,
a string subjacente é armazenada como uma string vazia (comprimento LEB128 0). Observe que uma string vazia não NULL
também tem comprimento LEB128 0; portanto, apenas o byte da máscara distingue os dois casos. Por exemplo, a seguinte consulta:
LowCardinality
LowCardinality é transparente, o formato Native usa uma codificação colunar baseada em dicionário. Uma coluna é codificada com um prefixo de versão, seguido de um dicionário de valores únicos e de um array de índices inteiros nesse dicionário.
Uma coluna pode ser definida como
LowCardinality(Nullable(T)), mas não é possível defini-la como Nullable(LowCardinality(T)) — isso sempre resultará em um erro do servidor.UInt64(LE) com valor 1, gravado uma vez por coluna. Em seguida, por bloco, é gravado o seguinte:
UInt64(LE)— campo de bitsIndexesSerializationType. Os bits 0–7 codificam a largura do índice (0 = UInt8, 1 = UInt16, 2 = UInt32, 3 = UInt64). O bit 8 (NeedGlobalDictionaryBit) nunca é definido no formato Native (o servidor gera uma exceção se ele for encontrado). O bit 9 indica que há chaves adicionais de dicionário. O bit 10 indica que o dicionário deve ser reinicializado.UInt64(LE)— número de chaves do dicionário, seguido pelas chaves serializadas em lote usando a codificação do tipo interno.UInt64(LE)— número de linhas, seguido pelos valores de índice serializados em lote usando a largura UInt apropriada.
String, 0 para tipos numéricos). Para LowCardinality(Nullable(T)), o índice 0 representa NULL, e as chaves são serializadas sem o wrapper Nullable.
Por exemplo, LowCardinality(String) com 5 linhas ['foo', 'bar', 'baz', 'foo', 'bar']:
LowCardinality(Nullable(String)), o índice 0 é NULL:
Array
- N offsets cumulativos
UInt64(little-endian, 8 bytes cada). A linhaitemoffset[i] - offset[i-1]elementos, comoffset[-1]implicitamente igual a 0. - Todos os elementos aninhados de todas as linhas, serializados em bloco de forma contígua.
Array(UInt32) com 3 linhas [[0, 10], [1, 11], [2, 12]]:
Array(String) com 4 linhas [[], ['0'], ['0','1'], ['0','1','2']]:
Map
Map(K, V) é codificado como Array(Tuple(K, V)) — offsets do array seguidos por todas as chaves e, em seguida, todos os valores. Isso difere de RowBinary, em que chaves e valores são intercalados em cada entrada.
Por exemplo, Map(String, UInt64) com 3 linhas [{'a':0,'b':10}, {'a':1,'b':11}, {'a':2,'b':12}]:
Variant
Variant é codificada da seguinte forma:
- Prefixo do modo dos discriminantes
UInt64(LE)(0= BASIC,1= COMPACT). A saída do formato Native normalmente usa BASIC (0); o modo COMPACT pode aparecer ao ler dados armazenados comuse_compact_variant_discriminators_serializationativado. - N discriminantes
UInt8, um por linha. - Os dados de cada tipo variante em uma coluna em bloco separada, contendo apenas as linhas correspondentes, na ordem dos discriminantes.
Variant(String, UInt32) com 5 linhas [0::UInt32, 'hello', NULL, 3::UInt32, 'hello'] (ordenado: String = 0, UInt32 = 1):
Dynamic
Dynamic como um prefixo de estrutura seguido de uma coluna Variant.
O prefixo de estrutura contém uma versão de serialização UInt64(LE), seguida pelo número de tipos dinâmicos (como VarUInt) e, então, pelos nomes dos tipos como strings. Na versão V1, a contagem de tipos é gravada duas vezes por compatibilidade. Os dados que vêm na sequência formam uma coluna Variant cuja lista de tipos inclui os tipos dinâmicos e um tipo interno SharedVariant, ordenados alfabeticamente.
Por exemplo, Dynamic com 5 linhas [0::UInt32, 'hello', NULL, 3::UInt32, 'hello']:
JSON
JSON em uma estrutura colunar. A codificação é complexa e depende da versão: consiste em um prefixo de estrutura com a versão de serialização, nomes de caminhos dinâmicos e o layout de dados compartilhados, seguido por caminhos tipados (cada um como uma coluna em bloco), caminhos dinâmicos (cada um como uma coluna Dynamic) e dados compartilhados para caminhos de overflow.
Para uma interoperabilidade mais simples, considere usar a configuração output_format_native_write_json_as_string=1, que serializa colunas JSON como strings simples de texto JSON (uma String por linha).