D
Datos y automatizacion M13 intermedio 14 min

Capitulo 03

ETL: el Patron, no la Herramienta

Por que hablar con soltura de extract-transform-load importa mas que memorizar Informatica o SSIS

El patron ETL/ELT, idempotencia, cargas incrementales, manejo de errores en pipelines y el panorama de herramientas del mercado.

ETL aparecio en el 21% de las ofertas, con stacks muy distintos

Lo que tienen en comun ofertas con AWS Athena, SQL Server + SSIS y BigQuery no es la herramienta — es el patron. Si entendes el patron, aprender la herramienta especifica de cada empresa es cuestion de dias.

3.1 El patron: Extract, Transform, Load

ETL (Extract, Transform, Load)

M13

Patron de integracion de datos en tres pasos: extraer de una o mas fuentes, transformar (limpiar, tipar, aplicar reglas de negocio, deduplicar) y cargar en un destino de consumo (data warehouse, datamart, tabla de BI).

#etl
ConceptoDescripcion
E Leer datos de la fuente: una base de datos, una API, archivos planos (CSV, JSON, Excel). El reto tipico: fuentes con formatos y calidad inconsistentes.
T Limpieza (nulos, duplicados), tipado correcto, aplicar reglas de negocio, unir con otras fuentes. Aqui vive la mayor parte del trabajo real de un Data Engineer/Analyst.
L Escribir el resultado en el destino: una tabla de un data warehouse, un datamart, un archivo consumido por BI. Full load (reemplaza todo) vs incremental (solo lo nuevo).
Por que pensar en 3 pasos separados y no un script monolitico

La alternativa naive es un unico script que lee, transforma y escribe todo junto — funciona hasta que algo falla a la mitad, y ahi no sabes si el problema fue de lectura, de una regla de negocio mal aplicada, o de la escritura. Separar Extract/Transform/Load en pasos identificables (aunque sea con funciones distintas en el mismo script) te permite loguear y reintentar cada paso de forma independiente, y reemplazar uno sin tocar los otros dos (ej. cambiar la fuente de un CSV a una API sin tocar la logica de transformacion).

Caso real: consolidar ventas de multiples sucursales

Un escenario tipico de retail (Falabella, Crossing Hurdles en la muestra de mercado): cada sucursal exporta un CSV de ventas diarias a una carpeta compartida. El Extract lee todos los CSV del dia, el Transform normaliza formatos de fecha/moneda distintos entre sucursales y elimina duplicados (una venta reportada dos veces por un reintento del POS), y el Load consolida todo en una tabla central que alimenta el dashboard ejecutivo del dia siguiente.

1. Mezclar reglas de negocio en el paso de Extract
✗ Filtrar 'solo ventas mayores a $10.000' directamente en la query de extraccion, escondiendo una regla de negocio donde nadie la espera.
✓ Extraer todo el dato crudo, y aplicar filtros/reglas de negocio explicitamente en el paso de Transform, donde son visibles y testeables.

3.2 ETL vs ELT: por que el cloud cambio el orden

ETL vs ELT

M13

ELT invierte el orden: carga los datos crudos primero en el destino, y transforma DESPUES usando el poder de computo del propio data warehouse (BigQuery, Snowflake). Es el patron dominante en arquitecturas cloud modernas.

#etl #cloud
Por que importa esta distincion

Antes, transformar datos fuera de la base (en un servidor ETL dedicado) tenia sentido porque la base no tenia capacidad de computo sobrante. Hoy, BigQuery y Snowflake escalan el computo bajo demanda — entonces tiene mas sentido cargar los datos crudos y transformarlos con SQL dentro del warehouse (herramientas como dbt formalizan este patron).

Caso real: por que el nicho 'Google Workspace analytics' usa ELT

El patron “BigQuery + Sheets + Looker Studio” que aparece en la muestra de mercado (LATAM Airlines) es ELT por definicion: los datos crudos de operaciones se cargan directo a BigQuery, y las transformaciones (agregaciones, joins, calculos) se escriben como vistas SQL dentro del mismo BigQuery, consumidas despues por Looker Studio. No existe un servidor ETL intermedio — todo el computo de transformacion vive en el warehouse.

1. Elegir ELT sin considerar el costo de computo dentro del warehouse
✗ Cargar datos crudos masivos y transformarlos con SQL complejo cada vez que alguien abre un dashboard, sin materializar resultados intermedios.
✓ Materializar (guardar como tabla) los resultados de transformaciones costosas que se repiten, en vez de recalcularlas en cada query — el costo de BigQuery/Snowflake es por computo/bytes escaneados.

3.3 Idempotencia: la propiedad que evita desastres

Idempotencia

M13

Propiedad de un proceso que produce el mismo resultado final sin efectos secundarios adicionales, sin importar cuantas veces se ejecute con la misma entrada. Un pipeline no idempotente que se reintenta tras un fallo puede duplicar datos.

#etl #pipelines
sql carga_no_idempotente_vs_idempotente.sql
-- MAL: si este INSERT corre dos veces (ej. por un retry automatico), duplica todas las filas
INSERT INTO ventas_consolidadas
SELECT * FROM ventas_raw WHERE fecha = '2026-07-24';

-- BIEN: MERGE (o "upsert") es idempotente — correrlo N veces da el mismo resultado
MERGE INTO ventas_consolidadas AS destino
USING (SELECT * FROM ventas_raw WHERE fecha = '2026-07-24') AS origen
ON destino.id = origen.id
WHEN MATCHED THEN UPDATE SET monto = origen.monto
WHEN NOT MATCHED THEN INSERT (id, fecha, monto) VALUES (origen.id, origen.fecha, origen.monto);
Por que diseñar para idempotencia desde el dia 1

La alternativa naive (un simple INSERT que asume que el pipeline siempre corre exactamente una vez) funciona perfecto hasta el primer fallo de red, timeout, o reintento automatico de un orquestador — momento en el que silenciosamente duplica datos y nadie lo nota hasta que el reporte financiero no cuadra. Diseñar con MERGE/upsert desde el principio cuesta poco mas de escribir y evita ese tipo de bug, que ademas es dificil de detectar despues (los datos duplicados parecen datos validos).

Caso real: reintento automatico de un orquestador

En un pipeline orquestado con Airflow, si una tarea falla por un timeout de red a mitad de la carga, el orquestador la reintenta automaticamente. Si esa tarea usa INSERT simple, el reintento duplica las filas que ya se habian cargado antes del timeout. Con MERGE, el reintento simplemente vuelve a aplicar el mismo resultado — sin duplicados, sin intervencion manual.

3.4 Full load vs carga incremental

Carga Incremental

M13

Estrategia que procesa solo los datos nuevos o modificados desde la ultima ejecucion (usando una marca de tiempo o un ID), en vez de recargar la tabla completa (full load) cada vez.

#etl

Un full load es simple pero costoso a escala; una carga incremental requiere llevar registro de “hasta donde se proceso” (un watermark), pero escala a volumenes grandes sin reprocesar todo el historico.

Caso real: cuando SI conviene full load

No toda tabla necesita carga incremental. Una tabla de dimension pequeña (ej. dim_sucursal con 50 filas) es mas simple de mantener con full load diario — el costo de reprocesar 50 filas es insignificante, y evitas la complejidad de manejar un watermark para una tabla que casi no cambia. La carga incremental se justifica cuando el volumen (millones de filas) hace que reprocesar todo sea costoso en tiempo o dinero — tipicamente la tabla de hechos, no las dimensiones.

1. Un watermark basado en 'hora de carga' en vez de 'hora del evento'
✗ Marcar el watermark con la hora en que corrio el pipeline, ignorando que datos con fecha anterior pueden llegar tarde (ej. una venta offline sincronizada al dia siguiente).
✓ Usar una ventana de tolerancia (ej. reprocesar los ultimos 3 dias en cada corrida) para capturar datos que llegan tarde, en vez de asumir que todo llega a tiempo.

3.5 Manejo de errores y logging

Que hacer si una fila falla

Un pipeline de produccion nunca debe tumbarse completo porque una fila tiene un dato malformado. El patron estandar: mover las filas problematicas a una tabla/archivo de “cuarentena” (dead-letter), loguear el error con contexto suficiente para depurar despues, y continuar procesando el resto.

3.6 Orquestacion: scheduling y dependencias

A nivel conceptual, cuando un pipeline tiene varios pasos con dependencias (extraer → transformar → cargar → notificar), se necesita un orquestador que sepa el orden, reintente pasos fallidos, y alerte si algo no corrio. Airflow es la referencia mas comun de la industria para esto.

3.7 El panorama de herramientas (para reconocer, no necesariamente dominar)

ConceptoDescripcion
Informatica/Talend/Pentaho Herramientas con interfaz grafica de arrastrar y soltar para definir flujos ETL, comunes en empresas grandes con stacks legacy. Aparecen en ofertas de banca/retail con stacks Microsoft/Oracle.
SSIS/SSAS/SSRS SQL Server Integration/Analysis/Reporting Services: el ecosistema ETL+BI de Microsoft. Comun en empresas con SQL Server como base principal.
dbt Herramienta moderna que formaliza el "T" del ELT como SQL versionado en Git, con tests y documentacion. Estandar de facto en stacks cloud-native modernos.
Airflow Define pipelines como codigo (DAGs en Python), con scheduling, reintentos y monitoreo. El orquestador mas mencionado en ofertas de Data Engineering.

3.8 Recursos

Articulo: dbt Labs: "What is ETL vs ELT?" (explicacion clara y actual del cambio de paradigma)
Curso: Apache Airflow: Getting Started (documentacion oficial)
Libro: "Designing Data-Intensive Applications" - Martin Kleppmann (fundamentos de pipelines confiables)

3.9 Preguntas de entrevista

Q: ¿Que harias si un pipeline ETL falla a mitad de camino, despues de haber cargado el 60% de las filas?

Depende de si el proceso es idempotente. Si lo es (usa MERGE/upsert), simplemente lo vuelvo a correr completo sin riesgo de duplicados. Si no lo es, necesito o bien un mecanismo de checkpoint (retomar desde donde fallo) o revertir la carga parcial antes de reintentar. La leccion de fondo: diseñar el pipeline para que sea seguro reintentarlo desde el principio es mejor que optimizar prematuramente con checkpoints complejos.

🪤 Responder solo 'lo vuelvo a correr' sin mencionar el riesgo de duplicados si el proceso no es idempotente.
Practica: pipeline ETL idempotente intermedio
  1. Elige un CSV publico con datos que se actualizan periodicamente (ej. un dataset de precios o clima).
  2. Escribi un script que extraiga, limpie/tipe, y cargue los datos en una tabla SQLite local.
  3. Usa un patron de upsert (INSERT OR REPLACE en SQLite) para que correr el script dos veces no duplique filas.
  4. Agrega manejo de errores: si una fila tiene un dato invalido, que se registre en un log y el proceso continue.