Tipos de dados
Numéricos
Os usuários que movem dados entre ClickHouse e Snowflake perceberão imediatamente que o
ClickHouse oferece mais granularidade na definição de tipos numéricos. Por exemplo, o
Snowflake oferece o tipo Number para valores numéricos. Isso exige que o usuário especifique a
precisão (número total de dígitos) e a escala (dígitos à direita do separador decimal),
até um total de 38. Declarações de inteiros são sinônimas de Number e simplesmente
definem precisão e escala fixas, com o mesmo intervalo. Essa conveniência
é possível porque modificar a precisão (a escala é 0 para inteiros) não afeta o
tamanho dos dados em disco no Snowflake — os bytes mínimos necessários são usados para um
determinado intervalo numérico no momento da gravação, no nível da micropartição. A escala, porém,
afeta o espaço de armazenamento, embora isso seja compensado por compressão. Um tipo Float64 oferece uma
faixa maior de valores, com perda de precisão.
Em contraste, o ClickHouse oferece múltiplos níveis de precisão com e sem sinal
para floats e inteiros. Com isso, você pode especificar com precisão
o nível necessário para inteiros, a fim de otimizar o armazenamento e o uso de memória. Um
tipo Decimal, equivalente ao tipo Number do Snowflake, também oferece o dobro de
precisão e escala, chegando a 76 dígitos. Além de um Float64 semelhante,
o ClickHouse também fornece um Float32 para situações em que a precisão é menos crítica e a
compressão é primordial.
Strings
ClickHouse e Snowflake adotam abordagens contrastantes para o armazenamento de
strings. No Snowflake, VARCHAR armazena caracteres Unicode em UTF-8, permitindo que o
usuário especifique um comprimento máximo. Esse comprimento não tem impacto no armazenamento nem
no desempenho, já que sempre é usado o número mínimo de bytes para armazenar uma string, e
serve apenas para impor restrições úteis para ferramentas downstream. Outros tipos, como
Text e NChar, são simplesmente aliases desse tipo. Já o ClickHouse
armazena todos os dados de string como bytes brutos com o tipo String
(sem necessidade de especificar comprimento), deixando a codificação a cargo do usuário, com
funções em tempo de consulta
disponíveis para diferentes codificações. Remetemos o leitor a "Opaque data argument"
para entender a motivação por trás disso. Assim, o String do ClickHouse é mais comparável
ao tipo Binary do Snowflake em termos de implementação. Tanto o Snowflake
quanto o ClickHouse
oferecem suporte a “collation”, permitindo que os usuários alterem a forma como as strings são ordenadas e comparadas.
Tipos semiestruturados
O Snowflake oferece suporte aos tipos VARIANT, OBJECT e ARRAY para dados
semiestruturados.
O ClickHouse oferece os tipos equivalentes Variant,
Object (agora preterido em favor do tipo JSON nativo) e Array.
Além disso, o ClickHouse tem o tipo JSON,
que substitui o agora preterido Object('json') e se destaca
pelo alto desempenho e pela eficiência de armazenamento em comparação com outros tipos JSON nativos.
O ClickHouse também oferece suporte a Tuples nomeadas e arrays de Tuples
por meio do tipo Nested,
permitindo que os usuários mapeiem explicitamente estruturas aninhadas. Isso permite que codecs e
otimizações de tipo sejam aplicados em toda a hierarquia, ao contrário do Snowflake, que
exige que o usuário use os tipos OBJECT, VARIANT e ARRAY para o objeto
externo e não permite tipagem interna explícita.
Essa tipagem interna também simplifica as consultas sobre valores numéricos aninhados no ClickHouse,
que não precisam de cast e podem ser usadas em definições de índice.
No ClickHouse, codecs e tipos otimizados também podem ser aplicados a subestruturas. Isso traz o benefício adicional de que a compressão com estruturas aninhadas continua excelente e comparável à de dados achatados. Em contraste, devido à incapacidade de aplicar tipos específicos a subestruturas, o Snowflake recomenda achatar os dados para obter compressão ideal. O Snowflake também impõe restrições de tamanho a esses tipos de dados.
Referência de tipos
| Snowflake | ClickHouse | Observação | |
|---|---|---|---|
NUMBER |
Decimal |
O ClickHouse oferece o dobro da precisão e da escala do Snowflake — 76 dígitos contra 38. | |
FLOAT, FLOAT4, FLOAT8 |
Float32, Float64 |
Todos os tipos de ponto flutuante no Snowflake são de 64 bits. | |
VARCHAR |
String |
||
BINARY |
String |
||
BOOLEAN |
Bool |
||
DATE |
Date, Date32 |
DATE no Snowflake oferece um intervalo de datas maior do que no ClickHouse; por exemplo, o mínimo para Date32 é 1900-01-01 e, para Date, 1970-01-01. Date no ClickHouse oferece armazenamento mais econômico (dois bytes). |
|
TIME(N) |
Sem equivalente direto, mas pode ser representado por DateTime e DateTime64(N). |
DateTime64 usa o mesmo conceito de precisão. |
|
TIMESTAMP - TIMESTAMP_LTZ, TIMESTAMP_NTZ, TIMESTAMP_TZ |
DateTime e DateTime64 |
DateTime e DateTime64 podem, opcionalmente, ter um parâmetro TZ definido para a coluna. Se ele não estiver presente, será usado o fuso horário do servidor. Além disso, há um parâmetro --use_client_time_zone disponível para o cliente. |
|
VARIANT |
JSON, Tuple, Nested |
O tipo JSON é experimental no ClickHouse. Esse tipo infere os tipos das colunas no momento da inserção. Tuple, Nested e Array também podem ser usados, como alternativa, para criar estruturas com tipagem explicitamente definida. |
|
OBJECT |
Tuple, Map, JSON |
Tanto OBJECT quanto Map são análogos ao tipo JSON no ClickHouse, em que as chaves são do tipo String. O ClickHouse exige que o valor seja consistente e fortemente tipado, enquanto o Snowflake usa VARIANT. Isso significa que os valores de chaves diferentes podem ter tipos diferentes. Se isso for necessário no ClickHouse, defina explicitamente a hierarquia usando Tuple ou recorra ao tipo JSON. |
|
ARRAY |
Array, Nested |
ARRAY no Snowflake usa VARIANT para os elementos — um supertipo. Já no ClickHouse, eles são fortemente tipados. |
|
GEOGRAPHY |
Point, Ring, Polygon, MultiPolygon |
Snowflake impõe um sistema de coordenadas (WGS 84), enquanto o ClickHouse o aplica no momento da consulta. | |
GEOMETRY |
Point, Ring, Polygon, MultiPolygon |
| Tipo do ClickHouse | Descrição |
|---|---|
IPv4 e IPv6 |
Tipos específicos para IP, que podem permitir um armazenamento mais eficiente do que no Snowflake. |
FixedString |
Permite usar um comprimento fixo em bytes, o que é útil para hashes. |
LowCardinality |
Permite que qualquer tipo seja codificado com Dicionário. Útil quando se espera uma cardinalidade < 100k. |
Enum |
Permite a codificação eficiente de valores nomeados em faixas de 8 ou 16 bits. |
UUID |
Para armazenamento eficiente de UUIDs. |
Array(Float32) |
Vetores podem ser representados como um Array de Float32 com funções de distância compatíveis. |
Por fim, o ClickHouse oferece a capacidade única de armazenar o estado intermediário de funções agregadas. Esse estado é específico da implementação, mas permite que o resultado de uma agregação seja armazenado e consultado posteriormente (com as funções de merge correspondentes). Em geral, esse recurso é usado por meio de uma visão materializada e, como mostrado abaixo, permite melhorar o desempenho de consultas específicas com custo mínimo de armazenamento, armazenando o resultado incremental de consultas sobre dados inseridos (mais detalhes aqui).