Skip to main content
O tipo de coluna JSON está pronto para produção a partir do ClickHouse 25.3+. Versões anteriores não são recomendadas para uso em produção.
Seus dados chegam em JSON. O ClickHouse oferece várias maneiras de armazená-los, desde colunas totalmente tipadas até uma String bruta. A escolha certa depende de quão previsível é o seu esquema e de você precisar ou não de consultas em nível de campo. Escopo: Esta página aborda decisões de modelagem de esquema para armazenar dados JSON. Ela não cobre formatos de entrada/saída JSON, funções JSON nem a sintaxe de consultas. Para mais contexto sobre o próprio tipo de coluna JSON, consulte Use JSON where appropriate. Pressupõe: Familiaridade com a criação de tabelas no ClickHouse, os conceitos básicos de MergeTree e a sintaxe de tipos de coluna.

Decisão rápida

  • Se cada campo tiver um tipo conhecido e estável, e o esquema raramente mudar Colunas tipadas
  • Se a maioria dos campos for estável, mas alguma seção for dinâmica ou imprevisível Híbrido (tipado + JSON)
  • Se toda a estrutura for dinâmica, com chaves que aparecem e desaparecem entre registros Coluna JSON nativa
  • Se os campos dinâmicos forem pares chave-valor com um tipo de valor consistente (por exemplo, tags de texto, métricas numéricas) Map em vez de JSON
  • Se você só armazena e recupera o blob JSON sem consultas em nível de campo Armazenamento opaco em String
Não confunda o formato JSON com o tipo de coluna JSON. Você pode inserir dados em formato JSON (via JSONEachRow, etc.) em colunas tipadas sem usar o tipo de coluna JSON. A decisão aqui é sobre tipos de coluna, não formatos de entrada.

Detalhes da abordagem

Colunas tipadas

Quando usar: A estrutura do JSON é totalmente conhecida na fase de modelagem. Os campos e tipos não mudam de um registro para outro. Mesmo estruturas aninhadas complexas (arrays de objetos, mapas aninhados) podem ser expressas com os tipos Array, Tuple e Nested. Desvantagens: Alterações no esquema exigem ALTER TABLE. Campos inesperados são descartados silenciosamente durante a inserção, a menos que o esquema seja atualizado.
Configuração
Verificação
Atenção a
  • Se você inserir dados JSON com JSONEachRow e o JSON contiver campos que não estão no esquema, o ClickHouse os descartará silenciosamente por padrão. Defina input_format_skip_unknown_fields como 0 se quiser que isso gere erros.

Híbrido (colunas tipadas + JSON)

Quando usar: Um conjunto principal de campos é estável (timestamps, IDs, códigos de status), mas parte do payload é dinâmica. Pense em atributos definidos pelo usuário, tags, metadados ou campos de extensão que variam entre os registros. Trade-offs: Desempenho total nas colunas tipadas e flexibilidade na coluna JSON. A coluna JSON ainda traz sobrecarga na inserção e custo de armazenamento para sua parte dinâmica.
Configuração
Verificação
Atenção
  • Use type hints em caminhos JSON que você já conhece. Essas indicações contornam a coluna discriminadora e armazenam o caminho como uma coluna tipada comum, com o mesmo desempenho e sem sobrecarga.
  • Use SKIP ou SKIP REGEXP para caminhos que você nunca consulta (metadados de depuração, IDs internos de tracing) para economizar armazenamento e reduzir a contagem de subcolunas.
  • Defina max_dynamic_paths de forma proporcional ao número de caminhos distintos que você realmente consulta. O padrão (1024) funciona na maioria dos casos. Reduza esse valor se sua seção dinâmica for pequena.
  • Não defina max_dynamic_paths acima de 10.000. Valores altos aumentam o consumo de recursos e reduzem a eficiência.
Chaves com pontoChaves com pontos (por exemplo, http.status_code) são tratadas como caminhos aninhados por padrão, então {"http.status_code": 200} é armazenado da mesma forma que {"http": {"status_code": 200}}. Isso é comum com atributos do OTel. Use type hints para controlar como caminhos com pontos são armazenados ou habilite json_type_escape_dots_in_keys (25.8+).

Coluna JSON nativa

Quando usar: A estrutura é realmente imprevisível, com chaves que aparecem e desaparecem entre registros. Esquemas gerados por usuários, sistemas de plugins ou ingestão em data lake em que você não controla o esquema upstream. Trade-offs: Inserções mais lentas do que em colunas tipadas. Leituras do objeto completo mais lentas do que em String. Sobrecarga de armazenamento devido ao gerenciamento de subcolunas. Funciona bem para consultas em nível de campo em caminhos específicos.
Configuração
Use o formato JSONAsObject ao inserir documentos JSON completos em uma coluna JSON. Ele trata cada linha de entrada como um objeto JSON completo mapeado para a coluna.Verificação
Fique atento a
  • Sem type hints, o ClickHouse infere os tipos por caminho com base nos primeiros valores que encontra. Se score chegar como "10" (string) em um registro e 10 (inteiro) em outro, o caminho receberá uma coluna discriminadora e as consultas ficarão mais lentas. Adicione indicações para caminhos com tipos conhecidos.
  • Quando a contagem de caminhos excede max_dynamic_paths, os valores excedentes são movidos para uma shared data structure com menor desempenho de consulta. Monitore com JSONDynamicPaths() e mantenha o limite abaixo de 10.000.
  • Cada caminho dinâmico aceita até max_dynamic_types (padrão 32) distinct data types. Se um único caminho exceder isso, os tipos extras passarão a usar o armazenamento variant compartilhado. Isso raramente importa, a menos que seus dados tenham tipos muito inconsistentes para o mesmo campo.

Armazenamento opaco em String

Quando usar: Documentos JSON são armazenados e recuperados por inteiro e depois encaminhados para uma aplicação, arquivados ou enviados para sistemas downstream. Sem filtragem por campo nem agregação dentro do ClickHouse. Trade-offs: inserts mais rápidos e esquema mais simples. Não há consulta em nível de campo sem parsing em tempo de execução (família JSONExtract), o que é lento em escala.
Configuração
Verificação
Atenção
  • Se os requisitos mudarem e depois você precisar de consultas por campo, será necessário criar uma nova tabela com colunas tipadas ou JSON e fazer backfill dos dados. Se houver qualquer chance de consultar campos individuais, comece com a abordagem híbrida.
  • As funções JSONExtract fazem parsing da string a cada consulta. Isso é aceitável para exploração ad hoc, mas não para dashboards de produção nem workloads com alto QPS.
  • Considere codecs de compressão (ZSTD) na coluna String se os payloads JSON forem grandes — a compressão costuma ser boa.

Comparação

Quando Map é mais adequado

Se seus campos dinâmicos forem pares chave-valor homogêneos — ou seja, todos os valores compartilham o mesmo tipo — Map(String, T) é mais simples e mais eficiente do que uma coluna JSON. Exemplos comuns: tags de string (Map(String, String)), métricas numéricas (Map(String, Float64)) ou feature flags (Map(String, Bool)).
Map oferece suporte à filtragem no nível da chave (tags['env'] = 'prod'), é mais barato de armazenar do que JSON e evita a sobrecarga de subcoluna do tipo JSON. Observe que as buscas de chave fazem uma varredura linear no map por padrão — isso é adequado para conjuntos pequenos de tags, mas, para maps com mais de 100 chaves, considere a serialização with_buckets. Use JSON quando os valores tiverem tipos mistos ou quando a estrutura tiver aninhamento — use Map quando forem pares chave-valor simples com um tipo de valor uniforme.
Última modificação em 23 de julho de 2026