Pular para o conteúdo principal

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

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).
Última modificação em 25 de junho de 2026