Map(K, V) almacena pares clave-valor.
A diferencia de otras bases de datos, los valores de tipo Map no tienen claves únicas en ClickHouse; es decir, un Map puede contener dos elementos con la misma clave.
(Esto se debe a que los Map se implementan internamente como Array(Tuple(K, V)).)
Puede usar la sintaxis m[k] para obtener el valor de la clave k en el Map m.
Además, m[k] recorre el Map; es decir, el tiempo de ejecución de la operación es lineal con respecto al tamaño del Map.
Parámetros
K— El tipo de las claves del Map. Cualquier tipo, excepto Nullable y LowCardinality anidado con tipos Nullable.V— El tipo de los valores del Map. Cualquier tipo.
Query
key2:
Query
Response
k no está en el mapa, m[k] devuelve el valor por defecto del tipo de valor; por ejemplo, 0 para los tipos enteros y '' para los tipos de cadena.
Para comprobar si existe una clave en un mapa, puede usar la función mapContains.
Query
Response
Conversión de Tuple a Map
Tuple() pueden convertirse en valores de tipo Map() mediante la función CAST:
Ejemplo
Query
Response
Lectura de las subcolumnas de Map
keys y values en algunos casos.
Ejemplo
Query
Response
Serialización en buckets de Map en MergeTree
Map en MergeTree se almacena como un único flujo Array(Tuple(K, V)).
Leer una sola clave con m['key'] requiere escanear toda la columna —todos los pares clave-valor de cada fila—, incluso si solo se necesita una clave.
En los Map con muchas claves distintas, esto se convierte en un cuello de botella.
La serialización en buckets (with_buckets) divide los pares clave-valor en varios subflujos independientes (buckets) aplicando un hash a la clave.
Cuando una consulta accede a m['key'], solo se lee del disco el bucket que contiene esa clave, omitiendo todos los demás buckets.
Activar la serialización en buckets
basic para las partes de nivel cero (creadas durante INSERT) y usar with_buckets solo para las partes fusionadas:
Cómo funciona
with_buckets:
- El número medio de claves por fila se calcula a partir de las estadísticas del bloque.
- El número de buckets se determina según la estrategia configurada (consulta Configuración).
- Cada par clave-valor se asigna a un bucket aplicando un hash a la clave:
bucket = hash(key) % num_buckets. - Cada bucket se almacena como un subflujo independiente con sus propias claves, valores y offsets.
- Un flujo de metadatos
buckets_inforegistra el número de buckets y sus estadísticas.
m['key']), el optimizador reescribe la expresión como una subcolumna de clave (m.key_<serialized_key>).
La capa de serialización calcula a qué bucket pertenece la clave solicitada y lee solo ese bucket desde el disco.
Cuando se lee el mapa completo (por ejemplo, SELECT m), se leen todos los buckets y se reconstruye el mapa original. Esto es más lento que la serialización basic debido a la sobrecarga de leer y fusionar varios subflujos.
El orden de las claves dentro de un valor de mapa puede diferir del orden de inserción original al usar la serialización
with_buckets. Las claves se distribuyen entre buckets mediante hash y se reconstruyen en orden de bucket, no en orden de inserción. Con la serialización basic, se conserva el orden de las claves de los mapas insertados.basic y with_buckets pueden coexistir en la misma tabla y se fusionan de forma transparente.
Configuración
Compensaciones de rendimiento
with_buckets frente a la serialización basic con distintos tamaños de Map (de 10 a 10.000 claves por fila). El número de buckets se determinó mediante la estrategia sqrt, con un máximo de 32. Los valores exactos dependen de los tipos de clave/valor, la distribución de los datos y el hardware.
Recomendaciones
- Mapas pequeños (< 32 claves de media): Mantén la serialización
basic. La sobrecarga de usar buckets no se justifica en mapas pequeños. El valor predeterminadomap_buckets_min_avg_size = 32lo aplica automáticamente. - Mapas medianos (32–100 claves): Usa
with_bucketscon la estrategiasqrtsi las consultas acceden con frecuencia a claves individuales. La mejora de velocidad es de 4–8x en búsquedas de una sola clave. - Mapas grandes (100+ claves): Usa
with_buckets. Las búsquedas de una sola clave son entre 16 y 49 veces más rápidas. Consideramap_serialization_version_for_zero_level_parts = 'basic'para mantener la velocidad deinsertcerca del valor de referencia. - Los escaneos completos del mapa dominan la carga de trabajo: Mantén
basic. La serialización con buckets añade una sobrecarga de ~2x en los escaneos completos. - Carga de trabajo mixta (algunas búsquedas de claves y algunos escaneos completos): Usa
with_bucketscon las partes de nivel cero configuradas enbasic. La optimizaciónPREWHERElee solo el bucket relevante para el filtro y luego lee el mapa completo únicamente para las filas coincidentes, lo que aporta una mejora neta significativa.
Enfoques alternativos
Map en buckets no se adapta a tu caso de uso, hay dos enfoques alternativos para mejorar el rendimiento del acceso por clave:
Uso del tipo de datos JSON
max_dynamic_paths pasan a una estructura de datos compartida, que puede usar la serialización advanced para optimizar las lecturas de una sola ruta. Consulta la entrada del blog para obtener una descripción detallada de la serialización advanced.
Usa
JSON cuando distintas claves necesiten distintos tipos de valor, cuando el conjunto de claves varíe significativamente entre filas o cuando las claves a las que se accede con frecuencia se conozcan de antemano y puedan declararse como rutas tipadas para acceder directamente a las subcolumnas.
Fragmentación manual en varias columnas de tipo Map
Map en varias columnas según el hash de la clave a nivel de la aplicación:
m{hash(key) % 4}. Durante las consultas, lea de la columna específica: m{hash('target_key') % 4}['target_key'].
La segmentación manual resulta útil cuando las fusiones verticales son importantes para reducir el uso de memoria durante las fusiones de tablas con muchas columnas, o cuando el número de segmentos debe permanecer fijo y controlarse explícitamente. Para la mayoría de los casos de uso, la serialización automática en buckets es más sencilla y suficiente.
Véase también
- función map()
- función CAST()
- combinador -Map para el tipo de dato Map