DuckDB: analítica rápida sin mover los datos
Actualizado: 2026-05-03
DuckDB[1] alcanzó la versión 1.0 en junio de 2024 y publicó la 1.1 en septiembre. Después de años siendo “esa cosa curiosa que usan los investigadores”, el proyecto ha llegado a un punto de madurez en el que empieza a desplazar herramientas con las que nadie pensaba competir: pandas, Spark en local e incluso, para muchos casos, el data warehouse en la nube. Este artículo explica, sin exageraciones, dónde encaja realmente y dónde no.
Puntos clave
- DuckDB es columnar y vectorizado: procesa datos por vectores de miles de elementos aprovechando SIMD, lo que lo acerca al límite teórico del hardware.
- Lee Parquet, CSV, JSON, S3 y URLs directamente sin importar los datos a una tabla interna.
- Para datasets de hasta cien gigabytes, supera a pandas en velocidad y a Snowflake en coste de fricción.
- La API es compatible con pandas, Polars y Arrow sin copiar memoria.
- No es un motor transaccional, no soporta escrituras concurrentes y no reemplaza al warehouse para datos de varios equipos.
Qué es y por qué importa
La descripción corta es fácil: DuckDB es a la analítica lo que SQLite es a las bases transaccionales. Una biblioteca embebida, sin servidor, sin daemon, sin credenciales, que se carga dentro del proceso de tu aplicación o notebook y expone un motor SQL completo.
Lo que lo hace diferente es el diseño interno. DuckDB es columnar y vectorizado: en lugar de procesar fila a fila, agrupa los valores en vectores de unos pocos miles de elementos y aplica cada operación sobre el vector entero. Eso permite aprovechar las instrucciones SIMD de la CPU, mantener los datos calientes en la caché L1/L2 y, en la práctica, acercarse mucho al límite teórico del hardware. Para cargas analíticas —agregaciones, joins, ventanas, escaneos masivos— esa decisión arquitectónica es la diferencia entre segundos y minutos.
La magnitud de la diferencia en la práctica:
| Tarea | pandas | DuckDB | Spark local |
|---|---|---|---|
| Consulta sobre 1 GB de CSV | 30 s | 2 s | 10 s |
| Agregación sobre 10 GB de Parquet | OOM | 5 s | 20 s |
| Join de dos tablas de 100 M filas | OOM | 15 s | 40 s |
En un portátil decente, DuckDB resuelve en segundos lo que pandas ni siquiera puede cargar y lo que Spark tarda decenas de segundos en coordinar entre sus ejecutores.
La diferencia entre OLAP y OLTP, otra vez
Conviene recordar por qué no todas las bases de datos sirven para lo mismo. Un sistema OLTP como PostgreSQL o MySQL está pensado para transacciones cortas y concurrentes que tocan pocas filas cada una —insertar un pedido, actualizar un saldo, leer un perfil de usuario. Los índices B-tree, el log de transacciones y el MVCC están optimizados para esa carga.
Un motor analítico vive en el extremo opuesto. Las consultas leen millones de filas pero solo tres o cuatro columnas, los joins son grandes, las agregaciones barren el dataset completo y la concurrencia de escritura es baja o inexistente. Almacenar los datos por columnas permite leer únicamente lo que la consulta pide, comprimir mucho mejor y aplicar operaciones vectorizadas. Por eso DuckDB gana frente a Postgres en estos escenarios: no porque Postgres sea lento, sino porque está optimizado para otra cosa.
Qué significa analítica sin mover los datos
La expresión analítica local suena modesta, pero describe un cambio de postura importante. Durante años, la respuesta por defecto a “tengo datos que analizar” era subirlos a un warehouse —Snowflake, BigQuery, Redshift— aunque fueran diez gigabytes. Se pagaba almacenamiento, se pagaba compute por consulta y se pagaba la complejidad de mover datos que cabían perfectamente en la memoria de una máquina moderna.
DuckDB invierte esa lógica. Un portátil con 32 GB de RAM y un SSD NVMe es capaz de ejecutar consultas sobre cientos de gigabytes de Parquet, streameando desde disco, sin llenar la memoria, sin clúster, sin factura mensual. El lee-archivos-directamente es la parte que más sorprende la primera vez: apuntas a un .parquet, a un glob de varios, a una ruta s3:// o a una URL https:// y el motor resuelve el acceso, la inferencia de esquema, los push-downs de predicado y la proyección de columnas por ti.
import duckdb
con = duckdb.connect()
con.execute("INSTALL httpfs; LOAD httpfs;")
df = con.execute("""
SELECT category, SUM(amount) AS total, COUNT(*) AS n
FROM 's3://bucket/ventas/*.parquet'
WHERE date >= '2024-01-01'
GROUP BY category
ORDER BY total DESC
""").df()Ese único bloque cubre tres ideas que antes requerían herramientas separadas: lectura streaming de un data lake, agregación analítica sobre varios archivos y entrega del resultado como DataFrame listo para graficar.
Cómo encaja en un proyecto real
El ejemplo canónico es reemplazar pandas en la fase de exploración y preparación de datos. La API de DuckDB es deliberadamente compatible con el ecosistema: puedes ejecutar SQL sobre un DataFrame de pandas, sobre uno de Polars, sobre un RecordBatch de Arrow o sobre archivos en disco, y devolver el resultado de nuevo en cualquiera de esos formatos, casi siempre sin copiar memoria.
Las extensiones amplían el motor con una línea:
httpfs: acceso a S3, GCS, Azure Blob y URLs HTTP.spatial: geometrías y análisis GIS con ST_*.json: funciones para semi-estructurados.sqliteypostgres: lectura directa de bases de datos externas.
En equipos más formales, DuckDB se ha convertido en el adaptador por defecto de dbt para desarrollo local: compilas, testeas y materializas modelos contra un fichero .duckdb en tu máquina antes de promocionar a producción. El flujo es idéntico al de producción en Snowflake o BigQuery —misma sintaxis SQL, mismo dbt— con latencia de segundos en lugar de minutos y sin coste de compute por consulta.
Si tu pipeline de datos termina alimentando tablas para analítica con SQL sobre Parquet, DuckDB y SQLite resuelven espacios distintos: DuckDB para analítica de alta cardinalidad, SQLite para aplicaciones de usuario o persistencia ligera.
DuckDB y LLM: analítica de embeddings
Un caso de uso reciente que ha ganado tracción es usar DuckDB para analítica sobre datasets de embeddings generados por modelos de lenguaje. Aunque no tiene el soporte de vector similarity search nativo de pgvector, sí permite:
- Cargar grandes matrices de embeddings desde Parquet.
- Calcular similitudes coseno como operaciones SQL vectorizadas.
- Filtrar y agregar sobre metadatos en el mismo query.
Para exploración de embeddings en fase de investigación o validación de pipelines RAG, DuckDB + Parquet es una combinación ligera y rápida antes de comprometerse con una base de datos vectorial en producción.
Dónde DuckDB no es la respuesta
La honestidad pide reconocer los límites:
- Multi-usuario con escrituras concurrentes: un escritor a la vez y muchos lectores. No es para aplicaciones de usuario final con transacciones paralelas.
- Streaming en tiempo real: no es Flink ni ksqlDB; DuckDB procesa datos batch, no flujos continuos.
- Datasets de producción a escala: cuando el dataset supera los cientos de gigabytes y lo consultan varios equipos con SLA, un warehouse gestionado sigue siendo la opción correcta.
- Operaciones transaccionales: para insertar pedidos o actualizar saldos, PostgreSQL o MySQL son la herramienta correcta.
Conclusión
Lo que hace interesante a DuckDB en este momento de madurez no es que sea rápido —hay motores rápidos desde hace décadas— sino que ha eliminado la fricción entre tener un problema analítico y resolverlo. No hay clúster que levantar, ni warehouse que aprovisionar, ni datos que mover, ni factura que vigilar. Se instala con pip, lee los archivos donde ya están y devuelve resultados en segundos. Para la enorme mayoría de cargas de trabajo por debajo del centenar de gigabytes, esa combinación hace que las alternativas parezcan desproporcionadas.