Skip to main content
El tipo de columna JSON está listo para producción a partir de ClickHouse 25.3+. No se recomienda usar versiones anteriores en producción.
Los datos llegan en formato JSON. ClickHouse ofrece varias formas de almacenarlos, desde columnas completamente tipadas hasta un String sin procesar. La opción adecuada depende de lo predecible que sea el esquema y de si se necesitan consultas a nivel de campo. Alcance: Esta página aborda decisiones de diseño de esquemas para almacenar datos JSON. No cubre los formatos de entrada/salida JSON, las funciones JSON ni la sintaxis de las consultas. Para más información sobre el propio tipo de columna JSON, consulte Use JSON where appropriate. Asume: Familiaridad con la creación de tablas de ClickHouse, los conceptos básicos de MergeTree y la sintaxis de los tipos de columna.

Decisión rápida

  • Si cada campo tiene un tipo conocido y estable, y el esquema rara vez cambia Columnas tipadas
  • Si la mayoría de los campos son estables, pero alguna parte es dinámica o impredecible Híbrido (columnas tipadas + JSON)
  • Si toda la estructura es dinámica, con claves que aparecen y desaparecen entre registros Columna JSON nativa
  • Si los campos dinámicos son pares clave-valor con un tipo de valor uniforme (p. ej., tags de texto, métricas numéricas) Map en lugar de JSON
  • Si solo se almacena y recupera el blob JSON sin consultas a nivel de campo Almacenamiento opaco en String
No confunda el formato JSON con el tipo de columna JSON. Puede insertar datos en formato JSON (mediante JSONEachRow, etc.) en columnas tipadas sin usar en absoluto el tipo de columna JSON. La decisión aquí se refiere a los tipos de columna, no a los formatos de entrada.

Detalles del enfoque

Columnas tipadas

Cuándo usarlo: La estructura del JSON se conoce por completo en tiempo de diseño. Los campos y los tipos no cambian entre registros. Incluso las estructuras anidadas complejas (arrays de objetos, mapas anidados) pueden expresarse con los tipos Array, Tuple y Nested. Consideraciones: Los cambios de esquema requieren ALTER TABLE. Los campos inesperados se descartan silenciosamente al insertar, a menos que se actualice el esquema.
Configuración
Verificación
Ten en cuenta
  • Si insertas datos JSON con JSONEachRow y el JSON contiene campos que no están en el esquema, ClickHouse los descarta silenciosamente de forma predeterminada. Establece input_format_skip_unknown_fields en 0 si quieres que se produzcan errores.

Híbrido (columnas tipadas + JSON)

Cuándo usarlo: Un conjunto básico de campos es estable (marcas de tiempo, ID, códigos de estado), pero parte del payload es dinámica. Por ejemplo, atributos definidos por el usuario, tags, metadatos o campos de extensión que varían entre registros. Compensaciones: Rendimiento completo en las columnas tipadas y flexibilidad en la columna JSON. La columna JSON sigue teniendo sobrecoste en las inserciones y coste de almacenamiento para su parte dinámica.
Configuración
Verificación
Tenga en cuenta
  • Use indicaciones de tipo en las rutas JSON que conozca de antemano. Estas indicaciones evitan la discriminator column y almacenan la ruta como una columna tipada normal, con el mismo rendimiento y sin sobrecoste.
  • Use SKIP o SKIP REGEXP para las rutas que nunca consulte (metadatos de depuración, ID internos de tracing) para ahorrar almacenamiento y reducir el número de subcolumnas.
  • Ajuste max_dynamic_paths de forma proporcional al número de rutas distintas que realmente consulta. El valor predeterminado (1024) funciona en la mayoría de los casos. Redúzcalo si su sección dinámica es limitada.
  • No establezca max_dynamic_paths por encima de 10,000. Los valores altos aumentan el consumo de recursos y reducen la eficiencia.
Claves con puntosLas claves con puntos (por ejemplo, http.status_code) se tratan como rutas anidadas de forma predeterminada, por lo que {"http.status_code": 200} se almacena igual que {"http": {"status_code": 200}}. Esto es habitual con los atributos de OTel. Use indicaciones de tipo para controlar cómo se almacenan las rutas con puntos, o habilite json_type_escape_dots_in_keys (25.8+).

Columna JSON nativa

Cuándo usarla: Cuando la estructura es realmente impredecible, con claves que aparecen y desaparecen entre registros. Resulta adecuada para esquemas generados por usuarios, sistemas de plugin o ingestión en data lakes donde no controlas el esquema de origen. Compensaciones: Inserciones más lentas que en las columnas tipadas. Lecturas del objeto completo más lentas que con String. Sobrecarga de almacenamiento por la gestión de subcolumnas. Funciona bien para consultas a nivel de campo sobre rutas específicas.
Configuración
Usa el formato JSONAsObject al insertar documentos JSON completos en una columna JSON. Trata cada línea de entrada como un objeto JSON completo asignado a la columna.Verificación
Ten en cuenta
  • Sin indicaciones de tipo, ClickHouse infiere los tipos de cada ruta a partir de los primeros valores que encuentra. Si score llega como "10" (cadena) en un registro y como 10 (entero) en otro, la ruta obtiene una columna discriminadora y las consultas se vuelven más lentas. Añade indicaciones para las rutas con tipos conocidos.
  • Cuando el número de rutas supera max_dynamic_paths, los valores desbordados se mueven a una estructura de datos compartida, lo que reduce el rendimiento de las consultas. Supervísalo con JSONDynamicPaths() y mantén el límite por debajo de 10.000.
  • Cada ruta dinámica admite hasta max_dynamic_types (32 de forma predeterminada) tipos de datos distintos. Si una sola ruta supera este valor, los tipos adicionales pasan al almacenamiento variant compartido. Esto rara vez importa, salvo que tus datos tengan tipos muy inconsistentes para el mismo campo.

Almacenamiento opaco en String

Cuándo usarlo: Los documentos JSON se almacenan y recuperan completos, y luego se pasan a una aplicación, se archivan o se reenvían a otros sistemas. Sin filtrado a nivel de campo ni agregación dentro de ClickHouse. Desventajas: Inserciones más rápidas y el esquema más simple. No hay consultas a nivel de campo sin análisis en tiempo de ejecución (familia JSONExtract), lo cual es lento a gran escala.
Configuración
Verificación
Ten en cuenta
  • Si los requisitos cambian y más adelante necesitas consultas a nivel de campo, tendrás que crear una tabla nueva con columnas tipadas o columnas JSON y rellenarla con los datos históricos. Si existe alguna posibilidad de que consultes campos individuales, empieza mejor con el enfoque híbrido.
  • Las funciones JSONExtract analizan la cadena en cada consulta. Es aceptable para exploración ad hoc, pero no para dashboards de producción ni workloads con QPS alto.
  • Considera códecs de compresión (ZSTD) en la columna String si los payloads JSON son grandes; comprime bien.

Comparación

Cuando conviene más usar Map

Si tus campos dinámicos son pares clave-valor homogéneos —todos los valores comparten el mismo tipo—, Map(String, T) es más sencillo y eficiente que una columna JSON. Algunos ejemplos habituales son: etiquetas de texto (Map(String, String)), métricas numéricas (Map(String, Float64)) o feature flags (Map(String, Bool)).
Map admite el filtrado a nivel de clave (tags['env'] = 'prod'), requiere menos almacenamiento que JSON y evita la sobrecarga de las subcolumnas del tipo JSON. Ten en cuenta que las búsquedas por clave recorren el mapa de forma lineal de manera predeterminada; esto está bien para conjuntos pequeños de etiquetas, pero para mapas con más de 100 claves, considera la serialización with_buckets. Usa JSON cuando los valores tengan tipos mixtos o la estructura tenga anidamiento; usa Map cuando sean pares clave-valor planos con un tipo de valor uniforme.
Última modificación el 23 de julio de 2026