Reemplazamos nuestro Snowflake de $8k/mes con DuckDB y Parquet
Esta es la historia de cómo pasamos de $8,000/mes en Snowflake a $0/mes — sin perder nada que le importara a nuestro equipo de 12 analistas.
El problema
Nuestra factura de Snowflake crecia 20% mes a mes. Teniamos:
- 2.3 TB de datos en 47 tablas
- 12 analistas ejecutando consultas
- 90% de las consultas eran simples: agregaciones, filtros, joins en 3-4 tablas
- La consulta promedio escaneaba menos de 50 GB
- El warehouse estaba inactivo 18 horas/dia
Estabamos pagando precios de data warehouse empresarial por cargas de trabajo que una laptop podia manejar.
El descubrimiento
Archivos Parquet en S3 + DuckDB = un data warehouse gratis para nuestra escala.
DuckDB puede:
- Leer Parquet directamente desde S3 (sin COPY INTO, sin staging)
- Ejecutar SQL complejo con joins, window functions, CTEs
- Procesar 50 GB en segundos en una sola máquina
- Cachear resultados para consultas repetidas
La pieza que faltaba era el tooling. Necesitabamos:
- Descubrimiento de tablas (que hay en el bucket?)
- Gestion de esquemas (que columnas existen?)
- Una interfaz de consulta para analistas
- Integracion con IA para usuarios de negocio
DataSpoc Lens proporcionaba todo eso.
La migración
Paso 1: Exportar de Snowflake a Parquet
Ya teniamos nuestros datos crudos en S3 (Snowflake cargaba desde ahi). Para las tablas curadas, exportamos:
pip install dataspoc-pipe
# We used Pipe to extract our Snowflake curated tables to Parquetdataspoc-pipe add snowflake \ --account xy12345.us-east-1 \ --database ANALYTICS \ --schema CURATED \ --tables revenue,customers,products,orders,sessions \ --destination s3://company-lakeLa migración única tomo 15 minutos para 2.3 TB.
Paso 2: Apuntar Lens al bucket
pip install dataspoc-lens
dataspoc-lens add-bucket s3://company-lakedataspoc-lens discoverSalida:
Discovered 47 tables in s3://company-lake: raw/postgres/orders (1.2M rows, 340 MB) raw/postgres/customers (89K rows, 12 MB) raw/postgres/products (2.4K rows, 1.1 MB) curated/finance/revenue (4.2M rows, 890 MB) curated/product/sessions (12M rows, 2.1 GB) ...Paso 3: Consultar cómo en Snowflake
El SQL es identico. Cada consulta que teniamos en Snowflake funcióno en DuckDB sin modificacion:
Snowflake:
-- snowflake worksheetSELECT DATE_TRUNC('month', order_date) AS month, product_category, SUM(amount) AS revenue, COUNT(DISTINCT customer_id) AS unique_customersFROM analytics.curated.revenueWHERE order_date >= '2024-01-01'GROUP BY 1, 2ORDER BY 1, 2;DataSpoc Lens (mismo SQL):
dataspoc-lens query "SELECT DATE_TRUNC('month', order_date) AS month, product_category, SUM(amount) AS revenue, COUNT(DISTINCT customer_id) AS unique_customersFROM curated.finance.revenueWHERE order_date >= '2024-01-01'GROUP BY 1, 2ORDER BY 1, 2"Mismos resultados. Cero costo. 1.2 segundos en lugar de 3.4 segundos (warehouse XS de Snowflake).
Paso 4: Darle a los analistas un shell interactivo
dataspoc-lens shellDataSpoc Lens Shell (DuckDB 0.10.1)Connected to: s3://company-lake (47 tables)Type .tables to list, .schema <table> to inspect, .quit to exit
lens> .tables┌─────────────────────────────────┬──────────┬─────────┐│ table │ rows │ size │├─────────────────────────────────┼──────────┼─────────┤│ curated.finance.revenue │ 4.2M │ 890 MB ││ curated.product.sessions │ 12M │ 2.1 GB ││ raw.postgres.orders │ 1.2M │ 340 MB ││ raw.postgres.customers │ 89K │ 12 MB ││ ... │ │ │└─────────────────────────────────┴──────────┴─────────┘
lens> SELECT COUNT(*) FROM curated.finance.revenue WHERE order_date >= '2024-01-01';┌──────────┐│ count │├──────────┤│ 1847293 │└──────────┘(0.4s)Los analistas que sabian SQL fueron productivos inmediatamente. Sin reentrenamiento.
Paso 5: AI Ask para usuarios de negocio
Para el CEO y PMs que no escriben SQL:
dataspoc-lens ask "What was our MRR growth last quarter?"Based on curated.finance.revenue:
MRR grew from $1.23M (Jul 2024) to $1.47M (Sep 2024), a 19.5% increaseover Q3. The strongest month was September (+8.2% MoM), driven byEnterprise plan upgrades.
SQL used: SELECT DATE_TRUNC('month', order_date) AS month, SUM(amount) AS mrr FROM curated.finance.revenue WHERE order_date >= '2024-07-01' AND order_date < '2024-10-01' AND revenue_type = 'recurring' GROUP BY 1 ORDER BY 1La IA muestra su trabajo — la consulta SQL exacta — para que los analistas puedan verificar.
Comparación de rendimiento
Hicimos benchmark con nuestras 20 consultas mas comunes:
| Tipo de consulta | Snowflake (XS) | DataSpoc Lens (DuckDB) |
|---|---|---|
| Agregacion simple (1 tabla) | 1.8s | 0.3s |
| Join 2 tablas + group by | 3.2s | 1.1s |
| Window function sobre 1M filas | 4.1s | 1.8s |
| Escaneo completo 12M filas | 6.7s | 4.2s |
| CTE complejo con 4 joins | 8.3s | 3.9s |
DuckDB fue mas rápido para cada consulta a nuestra escala. El secreto: sin viaje de ida y vuelta por red a un cloud warehouse, el formato columnar de Parquet significa que DuckDB solo lee las columnas que necesita, y las lecturas de S3 se paralelizan.
La comparación de costos
| Centro de costo | Snowflake | DataSpoc Lens |
|---|---|---|
| Computo (warehouse) | $6,200/mes | $0 |
| Almacenamiento (gestionado) | $1,800/mes | $0 (ya se paga S3) |
| Almacenamiento S3 | $47/mes | $47/mes (mismos datos) |
| Solicitudes GET de S3 | — | $12/mes |
| Licencia DataSpoc Lens | — | $0 (código abierto) |
| Total | $8,047/mes | $59/mes |
Ahorro anual: $95,856.
Lo que ganamos
Mas alla del ahorro en costos:
- Sin gestion de warehouse. Sin dimensionamiento, sin ajustar auto-suspend, sin monitorear creditos.
- Inicio instantaneo. Sin cold-start del warehouse (15-45 segundos en Snowflake).
- Desarrollo local. Los analistas pueden consultar los mismos datos localmente con
dataspoc-lens shell. - Nativo para IA. El servidor MCP significa que Claude, GPT y agentes internos consultan nuestros datos directamente.
- Portable. Sin lock-in a ningun proveedor. Parquet es un formato abierto.
Lo que perdimos (y advertencias honestas)
Este enfoque NO reemplaza a Snowflake si tienes:
| Requisito | Snowflake | DataSpoc Lens |
|---|---|---|
| 50+ analistas concurrentes | Lo maneja | Un solo usuario por proceso |
| Datos a escala de petabytes | Computo distribuido | Maquina única (limite ~100 GB efectivo) |
| RBAC granular | Roles nativos + politicas | Basado en IAM (nivel de bucket) |
| Time travel / versiónado | Integrado | Tu gestionas versiónes de Parquet |
| Semi-estructurado (JSON) | Tipo VARIANT | Funciones JSON de DuckDB (funcióna, menos elegante) |
| Gobernanza / linaje | Nativo + partners | DIY |
| Data sharing | Secure shares | Comparte el bucket (menos gobernado) |
Nuestra regla general: Si tus datos caben en la memoria de una sola máquina (hasta ~100 GB consultados activamente), probablemente no necesitas un cloud warehouse. Eso cubre el 80% de startups y empresas medianas.
El playbook de migración
Para equipos considerando esto:
- Audita tu uso de Snowflake. Ejecuta
ACCOUNT_USAGE.QUERY_HISTORY— verifica volumenes de datos y concurrencia. - Si el 90% de las consultas escanean < 50 GB: eres candidato.
- Exporta tablas curadas a Parquet en S3. Usa DataSpoc Pipe o
COPY INTOcon formato Parquet. - Configura Lens.
pip install dataspoc-lens && dataspoc-lens add-bucket s3://your-bucket - Ejecuta tus top 20 consultas. Valida correccion y rendimiento.
- Migra analistas gradualmente. Mantener Snowflake vivo por 1 mes cómo respaldo.
- Apaga el warehouse.
# The full migration in 4 commandspip install dataspoc-pipe dataspoc-lens
dataspoc-pipe add snowflake --account YOUR_ACCOUNT --tables ALL --destination s3://your-lakedataspoc-pipe run
dataspoc-lens add-bucket s3://your-lakedataspoc-lens shell # You're doneUn ano despues
12 meses despues de la migración:
- Ahorramos $95K en costos de Snowflake
- El rendimiento de consultas mejoro (sin cold starts)
- Los analistas estan mas contentos (shell instantaneo, AI Ask)
- Cero incidentes relacionados con la migración
- Agregamos servidor MCP para que bots de producto consulten datos autonomamente
Los $8K/mes estaban comprando cosas que no necesitabamos. Para equipos a nuestra escala, el cloud data warehouse es un problema resuelto — y la solución es gratis.