Saltar al contenido principal
Esta sección tiene como objetivo mostrar, a través de escenarios habituales, cómo utilizar distintas técnicas de rendimiento y optimización, como analizador de consultas, perfilado de consultas o evitar las columnas Nullable, para mejorar el rendimiento de las consultas en ClickHouse.

Entender el rendimiento de las consultas

El mejor momento para pensar en la optimización del rendimiento es cuando estás configurando tu esquema de datos antes de ingestar datos en ClickHouse por primera vez.  Pero, seamos sinceros: es difícil predecir cuánto crecerán tus datos o qué tipos de consultas se ejecutarán.  Si tienes un despliegue existente con algunas consultas que quieres mejorar, el primer paso es entender cómo funcionan esas consultas y por qué algunas se ejecutan en unos pocos milisegundos mientras que otras tardan más. ClickHouse dispone de un completo conjunto de herramientas para ayudarte a entender cómo se ejecuta tu consulta y qué recursos consume.  En esta sección, veremos esas herramientas y cómo utilizarlas. 

Consideraciones generales

Para entender el rendimiento de las consultas, veamos qué ocurre en ClickHouse cuando se ejecuta una consulta.  La siguiente parte está deliberadamente simplificada y omite algunos detalles; la idea no es abrumarte con ellos, sino ponerte al día con los conceptos básicos. Para obtener más información, puedes leer sobre el analizador de consultas A muy alto nivel, cuando ClickHouse ejecuta una consulta, ocurre lo siguiente: 
  • Análisis sintáctico y análisis de consultas
La consulta se analiza sintácticamente, se analiza y se crea un plan genérico de ejecución de consultas. 
  • Optimización de consultas
Se optimiza el plan de ejecución de la consulta, se descartan los datos innecesarios y se construye un pipeline de consultas a partir del plan de consulta. 
  • Ejecución del pipeline de consultas
Los datos se leen y se procesan en paralelo. Esta es la etapa en la que ClickHouse ejecuta realmente las operaciones de la consulta, como el filtrado, las agregaciones y la ordenación. 
  • Procesamiento final
Los resultados se combinan, se ordenan y se formatean en un resultado final antes de enviarse al cliente. En realidad, se aplican muchas optimizaciones, y en esta guía hablaremos un poco más sobre ellas, pero por ahora estos conceptos principales nos dan una buena idea de lo que ocurre entre bastidores cuando ClickHouse ejecuta una consulta.  Con esta visión general, examinemos las herramientas que proporciona ClickHouse y cómo podemos usarlas para hacer seguimiento de las métricas que afectan al rendimiento de las consultas. 

Conjunto de datos

Usaremos un ejemplo real para ilustrar cómo abordamos el rendimiento de las consultas.  Tomemos el conjunto de datos de NYC Taxi, que contiene datos de trayectos en taxi en NYC. Primero, ingestaremos el conjunto de datos de taxis de NYC sin ninguna optimización. A continuación se muestra el comando para crear la tabla e insertar datos desde un bucket de S3. Ten en cuenta que inferimos deliberadamente el esquema a partir de los datos, lo que no está optimizado.
Veamos el esquema de la tabla inferido automáticamente a partir de los datos.

Identifica las consultas lentas

Registros de consultas

De forma predeterminada, ClickHouse recopila y registra información sobre cada consulta ejecutada en los registros de consultas. Estos datos se almacenan en la tabla system.query_log Para cada consulta ejecutada, ClickHouse registra estadísticas como el tiempo de ejecución, el número de filas leídas y el uso de recursos, como la CPU, el uso de memoria o los aciertos de la caché del sistema de archivos.  Por lo tanto, el registro de consultas es un buen punto de partida para investigar consultas lentas. Puedes identificar fácilmente las consultas que tardan mucho en ejecutarse y ver la información de uso de recursos de cada una.  Veamos las cinco consultas de mayor duración en nuestro conjunto de datos de taxis de NYC.
El campo query_duration_ms indica cuánto tardó en ejecutarse esa consulta en particular. Al observar los resultados de los registros de consultas, vemos que la primera consulta tarda 2967ms en ejecutarse, lo que podría mejorarse.  También puede que quieras saber qué consultas están poniendo bajo presión al sistema; para ello, examina la consulta que consume más memoria o CPU. 
Aislemos las consultas de larga duración que encontramos y volvamos a ejecutarlas varias veces para entender el tiempo de respuesta.  En este punto, es fundamental desactivar la caché del sistema de archivos estableciendo la configuración enable_filesystem_cache en 0 para mejorar la reproducibilidad.
Resumámoslo en la tabla para facilitar la lectura. Veamos un poco mejor qué hacen estas consultas. 
  • La consulta 1 calcula la distribución de distancias de los trayectos con una velocidad media superior a 30 millas por hora.
  • La consulta 2 calcula el número y el coste medio de los trayectos por semana. 
  • La consulta 3 calcula la duración media de cada trayecto en el conjunto de datos.
Ninguna de estas consultas realiza un procesamiento especialmente complejo, salvo la primera, que calcula la duración del trayecto sobre la marcha cada vez que se ejecuta. Sin embargo, cada una tarda más de un segundo en ejecutarse, lo que, en el mundo de ClickHouse, es muchísimo tiempo. También podemos fijarnos en el uso de memoria de estas consultas: unos 400 MB por consulta es bastante. Además, todas parecen leer la misma cantidad de filas (es decir, 329.04 millones). Confirmemos rápidamente cuántas filas hay en esta tabla.
La tabla contiene 329,04 millones de filas, por lo que cada consulta realiza un escaneo completo de la tabla.

Sentencia EXPLAIN

Ahora que tenemos algunas consultas de larga duración, entendamos cómo se ejecutan. Para ello, ClickHouse admite el comando EXPLAIN. Es una herramienta muy útil que proporciona una vista detallada de todas las etapas de ejecución de una consulta sin necesidad de ejecutarla realmente. Aunque puede resultar abrumadora para quienes no son expertos en ClickHouse, sigue siendo una herramienta esencial para comprender cómo se ejecuta una consulta. La documentación ofrece una guía detallada sobre qué es la sentencia EXPLAIN y cómo utilizarla para analizar la ejecución de consultas. En lugar de repetir lo que ya se explica en esa guía, centrémonos en algunos comandos que nos ayudarán a identificar cuellos de botella en el rendimiento de ejecución de consultas. Explain indexes = 1 Comencemos con EXPLAIN indexes = 1 para inspeccionar el plan de consulta. El plan de consulta es un árbol que muestra cómo se ejecutará la consulta. En él se puede ver en qué orden se ejecutarán las cláusulas de la consulta. El plan de consulta que devuelve la sentencia EXPLAIN se lee de abajo hacia arriba. Probemos con la primera de nuestras consultas de larga ejecución.
El resultado es sencillo. La consulta comienza leyendo datos de la tabla nyc_taxi.trips_small_inferred. A continuación, se aplica la cláusula WHERE para filtrar las filas según los valores calculados. Los datos filtrados se preparan para la agregación y se calculan los cuantiles. Por último, el resultado se ordena y se genera la salida. Aquí podemos observar que no se utilizan claves primarias, lo cual tiene sentido ya que no definimos ninguna al crear la tabla. En consecuencia, ClickHouse realiza un escaneo completo de la tabla para la consulta. Explain Pipeline EXPLAIN Pipeline muestra la estrategia de ejecución concreta para la consulta. Allí se puede ver cómo ClickHouse ejecutó realmente el plan de consulta genérico que vimos anteriormente.
Aquí podemos observar el número de hilos utilizados para ejecutar la consulta: 59 hilos, lo que indica un alto grado de paralelización. Esto acelera la consulta, que tardaría más en ejecutarse en una máquina con menos recursos. El número de hilos que se ejecutan en paralelo puede explicar el elevado consumo de memoria que requiere la consulta. Lo ideal sería investigar todas las consultas lentas de la misma forma para identificar planes de consulta innecesariamente complejos y comprender el número de filas leídas por cada consulta y los recursos consumidos.

Metodología

Puede ser difícil identificar consultas problemáticas en una implementación de producción, ya que probablemente se esté ejecutando un gran número de consultas en un momento dado en su implementación de ClickHouse.  Si sabe qué usuario, base de datos o tablas están teniendo problemas, puede usar los campos user, tables o databases de system.query_logs para acotar la búsqueda.  Una vez que identifique las consultas que desea optimizar, puede empezar a trabajar en ellas. Un error común que cometen los desarrolladores en esta etapa es cambiar varias cosas a la vez, ejecutar experimentos ad hoc y, por lo general, acabar con resultados dispares y, lo que es más importante, sin entender bien qué hizo que la consulta fuera más rápida.  La optimización de consultas requiere un enfoque estructurado. No me refiero a benchmarks avanzados, sino a contar con un proceso sencillo para entender cómo afectan sus cambios al rendimiento de las consultas.  Empiece por identificar las consultas lentas en los registros de consultas y, a continuación, investigue posibles mejoras de forma aislada. Al probar la consulta, asegúrese de desactivar la caché del sistema de archivos. 
ClickHouse aprovecha el almacenamiento en caché para acelerar el rendimiento de las consultas en distintas etapas. Esto es bueno para el rendimiento de las consultas, pero durante la resolución de problemas podría ocultar posibles cuellos de botella de E/S o un esquema de tabla deficiente. Por esta razón, sugiero desactivar la caché del sistema de archivos durante las pruebas. Asegúrese de tenerla habilitada en la configuración de producción.
Una vez que haya identificado posibles optimizaciones, se recomienda implementarlas una por una para seguir mejor cómo afectan al rendimiento. A continuación se muestra un diagrama que describe el enfoque general. Por último, tenga cuidado con los valores atípicos; es bastante habitual que una consulta se ejecute lentamente, ya sea porque un usuario probó una consulta ad hoc costosa o porque el sistema estaba sometido a carga por alguna otra razón. Puede agrupar por el campo normalized_query_hash para identificar consultas costosas que se ejecutan con regularidad. Esas son probablemente las que querrá investigar.

Optimización básica

Ahora que ya tenemos un marco para hacer pruebas, podemos empezar a optimizar. El mejor punto de partida es analizar cómo se almacenan los datos. Como en cualquier base de datos, cuanto menos datos leamos, más rápido se ejecutará la consulta.  Según cómo hayas ingerido tus datos, es posible que hayas aprovechado las capacidades de ClickHouse para inferir el esquema de la tabla a partir de los datos ingeridos. Aunque esto resulta muy práctico para empezar, si quieres optimizar el rendimiento de las consultas, tendrás que revisar el esquema de los datos para que se ajuste lo mejor posible a tu caso de uso.

Nullable

Como se describe en la documentación de buenas prácticas, evita las columnas Nullable siempre que sea posible. Es tentador usarlas con frecuencia, ya que hacen más flexible el mecanismo de ingestión de datos, pero afectan negativamente al rendimiento porque cada vez hay que procesar una columna adicional. Ejecutar una consulta SQL que cuente las filas con un valor NULL puede revelar fácilmente qué columnas de tus tablas realmente necesitan ser Nullable.
Solo tenemos dos columnas con valores NULL: mta_tax y payment_type. El resto de los campos no debería usar una columna Nullable.

Baja cardinalidad

Una optimización fácil de aplicar a los valores String es aprovechar al máximo el tipo de dato LowCardinality. Como se describe en la documentación sobre baja cardinalidad, ClickHouse aplica codificación por diccionario a las columnas LowCardinality, lo que aumenta significativamente el rendimiento de las consultas.  Una regla práctica sencilla para determinar qué columnas son buenas candidatas para LowCardinality es que cualquier columna con menos de 10.000 valores únicos es una candidata ideal. Puede usar la siguiente consulta SQL para encontrar columnas con pocos valores únicos.
Dado que tienen baja cardinalidad, esas cuatro columnas, ratecode_id, pickup_location_id, dropoff_location_id y vendor_id, son buenas candidatas para el tipo de campo LowCardinality.

Optimizar el tipo de dato

ClickHouse admite una gran cantidad de tipos de datos. Asegúrate de elegir el tipo de dato más pequeño posible que se ajuste a tu caso de uso para optimizar el rendimiento y reducir el espacio de almacenamiento de tus datos en disco.  Para los números, puedes consultar el valor mínimo y máximo de tu conjunto de datos para verificar si la precisión actual se ajusta a los valores reales de tu conjunto de datos. 
Para las fechas, debes elegir una precisión acorde con tu conjunto de datos y que se adapte mejor a las consultas que piensas ejecutar.

Aplicar las optimizaciones

Vamos a crear una nueva tabla para usar el esquema optimizado y reingestar los datos.
Volvemos a ejecutar las consultas con la nueva tabla para comprobar la mejora.  Observamos algunas mejoras tanto en el tiempo de consulta como en el uso de memoria. Gracias a la optimización del esquema de datos, reducimos el volumen total de datos, lo que se traduce en un menor consumo de memoria y en menos tiempo de procesamiento.  Comprobemos el tamaño de las tablas para ver la diferencia. 
La nueva tabla es considerablemente más pequeña que la anterior. Observamos una reducción de alrededor del 34 % en el espacio en disco de la tabla (7.38 GiB frente a 4.89 GiB).

La importancia de las claves primarias

Las claves primarias en ClickHouse funcionan de forma distinta a como lo hacen en la mayoría de los sistemas de bases de datos tradicionales. En esos sistemas, las claves primarias garantizan la unicidad y la integridad de los datos. Cualquier intento de insertar valores duplicados de clave primaria se rechaza, y normalmente se crea un índice basado en B-tree o hash para realizar búsquedas rápidas.  En ClickHouse, el objetivo de la clave primaria es distinto; no garantiza la unicidad ni contribuye a la integridad de los datos. En cambio, está diseñada para optimizar el rendimiento de las consultas. La clave primaria define el orden en que los datos se almacenan en disco y se implementa como un índice disperso que almacena punteros a la primera fila de cada gránulo.
Los gránulos en ClickHouse son las unidades de datos más pequeñas que se leen durante la ejecución de consultas. Contienen hasta un número fijo de filas, determinado por index_granularity, con un valor predeterminado de 8192 filas. Los gránulos se almacenan de forma contigua y se ordenan según la clave primaria. 
Elegir un buen conjunto de claves primarias es importante para el rendimiento y, de hecho, es habitual almacenar los mismos datos en distintas tablas y usar diferentes conjuntos de claves primarias para acelerar un conjunto específico de consultas.  Otras opciones compatibles con ClickHouse, como Projection o una vista materializada, permiten usar un conjunto diferente de claves primarias sobre los mismos datos. La segunda parte de esta serie de blogs tratará este tema con más detalle. 

Elegir claves primarias

Elegir el conjunto adecuado de claves primarias es un tema complejo, y puede requerir concesiones y experimentos para encontrar la mejor combinación.  Por ahora, seguiremos estas prácticas sencillas: 
  • Usa campos que se utilicen para filtrar en la mayoría de las consultas
  • Elige primero las columnas con menor cardinalidad 
  • Considera incluir un componente temporal en tu clave primaria, ya que filtrar por tiempo en un conjunto de datos con timestamp es bastante común. 
En nuestro caso, vamos a experimentar con las siguientes claves primarias: passenger_count, pickup_datetime y dropoff_datetime La cardinalidad de passenger_count es baja (24 valores únicos) y se usa en nuestras consultas lentas. También añadimos campos de timestamp (pickup_datetime y dropoff_datetime), ya que suelen usarse para filtrar. Crea una nueva tabla con las claves primarias y vuelve a reingestar los datos.
Luego volvemos a ejecutar nuestras consultas. Recopilamos los resultados de los tres experimentos para ver las mejoras en el tiempo transcurrido, las filas procesadas y el consumo de memoria. 
Consulta 1
Ejecución 1Ejecución 2Ejecución 3
Tiempo transcurrido1.699 sec1.353 sec0.765 sec
Filas procesadas329.04 millones329.04 millones329.04 millones
Memoria máxima440.24 MiB337.12 MiB444.19 MiB
Consulta 2
Ejecución 1Ejecución 2Ejecución 3
Tiempo transcurrido1.419 sec1.171 sec0.248 sec
Filas procesadas329.04 millones329.04 millones41.46 millones
Memoria máxima546.75 MiB531.09 MiB173.50 MiB
Consulta 3
Ejecución 1Ejecución 2Ejecución 3
Transcurrido1.414 sec1.188 sec0.431 sec
Filas procesadas329.04 millones329.04 millones276.99 millones
Memoria máxima451.53 MiB265.05 MiB197.38 MiB
Podemos ver una mejora significativa tanto en el tiempo de ejecución como en el uso de memoria.  La consulta 2 es la que más se beneficia de la clave primaria. Veamos en qué se diferencia el plan de consulta generado con respecto al anterior.
Gracias a la clave primaria, solo se ha seleccionado un subconjunto de los gránulos de la tabla. Solo con eso ya mejora enormemente el rendimiento de la consulta, porque ClickHouse tiene que procesar muchos menos datos.

Siguientes pasos

Esperamos que esta guía te haya dado una buena idea de cómo investigar consultas lentas con ClickHouse y cómo hacerlas más rápidas. Si quieres profundizar en este tema, puedes leer sobre el analizador de consultas y el perfilado para entender mejor cómo ejecuta ClickHouse tu consulta. A medida que te familiarices más con las particularidades de ClickHouse, te recomendamos leer sobre las claves de partición y los índices de omisión de datos para conocer técnicas más avanzadas que puedes utilizar para acelerar tus consultas.
Última modificación el 19 de junio de 2026