ClickHouse desde cero (I): instalación y primeros pasos
Primera entrega de la serie ClickHouse desde cero a pro. Tiempo de lectura estimado: 9 minutos.
Arrancamos una serie de cinco posts sobre ClickHouse. La idea es ir de no haber tocado nunca ClickHouse a ser capaz de diseñar, optimizar y operar un cluster en producción. Nada de teoría de relleno: lo que se usa el día que tu empresa te dice "oye, tenemos 500 millones de CDRs mensuales, ¿montamos analytics?".
Si todavía tienes dudas sobre cuándo tiene sentido usar ClickHouse frente a PostgreSQL, el post ClickHouse para desarrolladores que vienen de PostgreSQL es una buena introducción previa. En esta serie doy por supuesto que ya has decidido que lo necesitas.
Qué es ClickHouse, en una frase
ClickHouse es una base de datos columnar, distribuida y orientada a analítica que habla un dialecto propio de SQL. Fue creada en Yandex para procesar los logs de Yandex.Metrica (el equivalente ruso de Google Analytics) y hoy se usa en empresas como Cloudflare, Uber, eBay o GitLab para analítica en tiempo real sobre volúmenes de cientos de miles de millones de filas.
Lo que la hace especial:
- Compresión brutal: ratios de 10:1 o 20:1 son normales.
- Velocidad de escaneo: cientos de millones de filas por segundo por core.
- Escalado horizontal: sharding y replicación incorporados.
- SQL familiar: si sabes SQL, puedes empezar el mismo día.
No está diseñada para transacciones, ni para UPDATE/DELETE frecuentes, ni para consultas por clave primaria al estilo OLTP. Eso sigue siendo trabajo de PostgreSQL o MySQL.
Opciones de instalación
Hay tres caminos razonables para empezar:
- Paquetes
.deb/.rpmsobre un servidor Linux. La opción clásica para producción. - Docker. La más rápida para probar en local.
- ClickHouse Cloud. El servicio gestionado oficial, con free tier.
Para esta serie vamos a usar Docker porque es reproducible y no mete ficheros en tu sistema. Todo lo que aprendas aplica igual a una instalación nativa.
Arrancar un ClickHouse local con Docker
docker run -d \
--name clickhouse \
-p 8123:8123 \
-p 9000:9000 \
-v clickhouse-data:/var/lib/clickhouse \
--ulimit nofile=262144:262144 \
clickhouse/clickhouse-server:latest
Algunos detalles importantes:
- El puerto 8123 es el interfaz HTTP (útil para cURL, Grafana, drivers).
- El puerto 9000 es el protocolo nativo (TCP binario, mucho más rápido).
- El volumen
clickhouse-datapersiste los datos entre reinicios. - El
ulimites una recomendación oficial: ClickHouse abre muchos ficheros cuando los parts se multiplican.
Comprueba que arranca:
curl http://localhost:8123/ping
# Ok.
Y entra al cliente interactivo:
docker exec -it clickhouse clickhouse-client
Instalación nativa en Debian/Ubuntu
Para referencia, si prefieres paquetes:
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg] \
https://packages.clickhouse.com/deb stable main" \
| sudo tee /etc/apt/sources.list.d/clickhouse.list
sudo apt-get update
sudo apt-get install -y clickhouse-server clickhouse-client
sudo systemctl enable --now clickhouse-server
Configuración en /etc/clickhouse-server/, datos en /var/lib/clickhouse/, logs en /var/log/clickhouse-server/.
El cliente de consola
clickhouse-client es la herramienta con la que vas a pasar el 80% del tiempo mientras aprendes. Es mucho más cómodo que psql: soporta multilínea nativa, autocompletado, formatos de salida, y puede ejecutar consultas desde ficheros directamente.
Dentro del cliente, estos comandos son los que más vas a usar:
SHOW DATABASES;
SHOW TABLES FROM system;
DESCRIBE TABLE system.numbers;
La base de datos system es un pequeño tesoro: contiene metadatos sobre tablas, consultas en curso, métricas internas, merges en marcha, procesos... volveremos a ella a menudo en la entrega V.
Formatos de salida útiles al hacer consultas one-shot:
clickhouse-client --query "SELECT count() FROM system.numbers LIMIT 1000000" \
--format PrettyCompact
clickhouse-client --query "SELECT number FROM system.numbers LIMIT 5" \
--format JSONEachRow
PrettyCompact, TabSeparated, CSV, CSVWithNames, JSONEachRow, Parquet... ClickHouse soporta más de 70 formatos de entrada y salida. Esto es más útil de lo que parece: te permite consumir ficheros externos sin herramientas intermedias.
Tu primera tabla
Vamos con un ejemplo realista: una tabla de eventos de tráfico web.
CREATE DATABASE blog;
CREATE TABLE blog.pageviews (
timestamp DateTime,
user_id UInt64,
path String,
referrer String,
country LowCardinality(String),
device LowCardinality(String),
duration_ms UInt32
)
ENGINE = MergeTree()
ORDER BY (timestamp, user_id);
Tres piezas importantes que vamos a diseccionar en la entrega II:
ENGINE = MergeTree(): el motor de tabla. MergeTree es el que vas a usar el 95% del tiempo. Define cómo se almacenan los datos en disco.ORDER BY: la decisión de diseño más importante que vas a tomar. Determina el orden físico de los datos y qué consultas serán rápidas.LowCardinality(String): tipo optimizado para strings con pocos valores distintos (países, dispositivos, estados). Comprime mejor y escanea más rápido.
Tu primer INSERT
ClickHouse prefiere inserts en batch grande, no fila a fila. Un antipatrón clásico es insertar una fila por petición HTTP: destroza el rendimiento y llena el disco de parts pequeñas que luego hay que mergear.
Vamos a generar datos sintéticos aprovechando system.numbers:
INSERT INTO blog.pageviews
SELECT
now() - toIntervalSecond(number % 86400) AS timestamp,
number % 10000 AS user_id,
['/', '/post/foo', '/post/bar', '/about', '/search'][number % 5 + 1] AS path,
['google.com', 'direct', 'twitter.com', 'hn'][number % 4 + 1] AS referrer,
['ES', 'FR', 'DE', 'US', 'MX'][number % 5 + 1] AS country,
['mobile', 'desktop', 'tablet'][number % 3 + 1] AS device,
rand() % 30000 AS duration_ms
FROM system.numbers
LIMIT 1000000;
Un millón de filas generadas en décimas de segundo. system.numbers es una tabla virtual infinita que devuelve enteros consecutivos: una herramienta fantástica para pruebas.
Tus primeros SELECT
-- Cuántas filas tenemos
SELECT count() FROM blog.pageviews;
-- Top 5 páginas
SELECT path, count() AS views
FROM blog.pageviews
GROUP BY path
ORDER BY views DESC
LIMIT 5;
-- Tráfico por país y hora
SELECT
country,
toStartOfHour(timestamp) AS hour,
count() AS views,
avg(duration_ms) AS avg_ms
FROM blog.pageviews
GROUP BY country, hour
ORDER BY hour DESC, views DESC
LIMIT 20;
Fíjate en el tiempo de ejecución que te muestra el cliente al final de cada consulta (Elapsed: 0.024 sec.). Con un millón de filas estamos en el rango de milisegundos. Con cien millones, probablemente sigas bajo el segundo si las consultas aprovechan la clave de ordenación.
Qué ha cambiado respecto a PostgreSQL
Si vienes de PostgreSQL, en este punto notarás varias cosas raras:
- No has creado ningún índice y las consultas vuelan.
- No hay
SERIAL,AUTO_INCREMENTninextval. En ClickHouse no se usan. INSERTmultilínea de un millón de filas tarda un suspiro y no bloquea nada.- No hay que hacer
VACUUMniANALYZE. - Hay un tipo llamado
LowCardinalityque PostgreSQL no tiene.
Todo esto tiene una explicación y está conectado al diseño columnar. Lo veremos en detalle en la siguiente entrega.
Por dónde seguir
Ya tienes un ClickHouse corriendo, sabes meter datos y consultarlos. En los próximos posts de la serie:
- II: tipos de datos y MergeTree — el sistema de tipos,
LowCardinality,Nullable, y cómo elegir la clave de ordenación. - III: consultas analíticas en profundidad — funciones de agregación, arrays, window functions, sampling.
- IV: materialized views, projections y TTL — pre-agregar datos y que una consulta de 10 segundos tarde 10 milisegundos.
- V: producción, replicación y clusters — ReplicatedMergeTree, ClickHouse Keeper, sharding, backups y monitorización.
Si estás pensando en introducir ClickHouse en un proyecto real, la comparativa con PostgreSQL te ayudará a justificar la decisión ante el equipo.