# ClickHouse desde cero (I): instalación y primeros pasos

*Primera entrega de la serie **[ClickHouse desde cero a pro](/search?tag=clickhouse-desde-cero)**. 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](/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:

1. **Paquetes `.deb` / `.rpm`** sobre un servidor Linux. La opción clásica para producción.
2. **Docker**. La más rápida para probar en local.
3. **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

```bash
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-data` persiste los datos entre reinicios.
- El `ulimit` es una recomendación oficial: ClickHouse abre muchos ficheros cuando los *parts* se multiplican.

Comprueba que arranca:

```bash
curl http://localhost:8123/ping
# Ok.
```

Y entra al cliente interactivo:

```bash
docker exec -it clickhouse clickhouse-client
```

### Instalación nativa en Debian/Ubuntu

Para referencia, si prefieres paquetes:

```bash
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:

```sql
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](/post/clickhouse-desde-cero-v-produccion-replicacion-y-clusters).

Formatos de salida útiles al hacer consultas one-shot:

```bash
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.

```sql
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](/post/clickhouse-desde-cero-ii-tipos-de-datos-y-mergetree):

- **`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`:

```sql
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

```sql
-- 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_INCREMENT` ni `nextval`. En ClickHouse no se usan.
- `INSERT` multilínea de un millón de filas tarda un suspiro y no bloquea nada.
- No hay que hacer `VACUUM` ni `ANALYZE`.
- Hay un tipo llamado `LowCardinality` que 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](/post/clickhouse-desde-cero-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](/post/clickhouse-desde-cero-iii-consultas-analiticas-en-profundidad)** — funciones de agregación, arrays, window functions, sampling.
- **[IV: materialized views, projections y TTL](/post/clickhouse-desde-cero-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](/post/clickhouse-desde-cero-v-produccion-replicacion-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](/post/clickhouse-para-desarrolladores-que-vienen-de-postgresql) te ayudará a justificar la decisión ante el equipo.
