El problema
Cuando conectás tu pipeline a una base de datos origen, tenés que decidir cómo vas a extraer los datos. La pregunta parece simple: ¿traigo todo o solo lo nuevo?
Pero detrás de esa pregunta hay otra más importante: ¿cuánto confío en que el origen me va a decir qué cambió?
Muchos equipos eligen el mecanismo de extracción por eficiencia (traer menos datos, gastar menos cómputo) sin evaluar si el origen puede sostener ese contrato. Después aparecen los problemas: registros que se pierden, modificaciones que no se capturan, deletes que nunca llegan.
Los tres mecanismos
Las estrategias de extracción se pueden agrupar en tres grandes categorías. Cada una tiene un presupuesto distinto sobre qué tan confiable es la información que te da el origen.
Full refresh
Te conectás a la tabla y te traés todo. Cada ejecución extrae la tabla completa y reemplaza lo que tenías en destino.
Presupuesto de confianza: ninguno. No necesitás que el origen te diga qué cambió porque te traés todo.
Ventajas:
- No dependés de detectar cambios individuales; si el snapshot de origen está completo, recuperás modificaciones y borrados.
- La implementación es trivial.
- No dependés de que el origen mantenga campos de auditoría.
Costos:
- Ineficiente en tablas grandes (extraés millones de registros cuando quizás cambiaron cientos).
- Carga sobre la base origen (queries pesadas, locks potenciales).
- Más cómputo y almacenamiento en destino.
Incremental por cursor
Usás un campo de la tabla origen (generalmente un timestamp de modificación o un ID autoincremental) para traer solo los registros nuevos o modificados desde la última ejecución.
Presupuesto de confianza: alto. Asumís que el campo cursor se actualiza correctamente cada vez que un registro cambia.
Ventajas:
- Eficiente: traés solo lo que cambió.
- Menos carga sobre el origen.
- Menos cómputo y almacenamiento.
Costos:
- Si el campo cursor no se actualiza (porque el backend no lo hace, porque alguien tocó la base a mano, porque el ORM no lo contempla), perdés modificaciones.
- No capturás deletes: un registro borrado no aparece en tu query incremental.
- Dependés de que alguien del otro lado mantenga ese contrato.
CDC (Change Data Capture)
Leés el transaction log de la base origen. Cada operación (insert, update, delete) queda registrada ahí, y vos la consumís para replicar los cambios en destino.
Presupuesto de confianza: bajo. El transaction log es un mecanismo interno de la base, no depende de que alguien mantenga un campo de auditoría.
Ventajas:
- Capturás todo: inserts, updates y deletes.
- Reducís mucho el riesgo de omitir cambios, porque consumís el registro transaccional que la base ya genera.
- Menos intrusivo: no hacés queries pesadas contra la base, leés el log que la base ya genera.
Costos:
- Complejidad operativa: hay que activar el mecanismo en la base origen, configurar herramientas como Debezium, gestionar el log que se va llenando.
- Requiere coordinación con el equipo que administra la base.
- Más orientado a casos de streaming o near-realtime.
Cómo elegir
La elección no es solo técnica. Depende de cuánto control tenés sobre el origen y cuánto podés confiar en que el contrato se va a mantener.
Si no controlás el origen y no tenés garantías sobre el campo de timestamp: andá por full refresh. Sí, es ineficiente. Pero te ahorrás el problema de descubrir tres meses después que perdiste modificaciones porque el backend no actualizaba el campo updated_at.
Si el origen tiene un campo de auditoría confiable y alguien se hace responsable de mantenerlo: podés usar incremental. Pero monitorealo. Validá que los registros que esperás ver aparezcan. No asumas que funciona solo porque no falló.
Si necesitás capturar deletes o tenés requerimientos de latencia baja: CDC es el camino. Pero implica coordinación con el equipo de la base y más complejidad operativa.
La recomendación general: cuando no estés seguro, preferí full refresh. Es menos eficiente pero más confiable. El costo de extraer datos de más es menor que el costo de perder datos y tener que explicar por qué tu reporte no cuadra.
El problema de los deletes
Un caso que merece atención especial: los registros borrados.
Con full refresh, los capturás implícitamente (si el registro no está en origen, no aparece en destino después del reemplazo).
Con incremental por cursor, no los capturás. El registro se borró, ya no existe, tu query incremental no lo ve. Si hacés append o merge, el registro sigue viviendo en tu destino aunque ya no exista en origen.
Con CDC, los capturás explícitamente (el delete queda en el transaction log).
Si tu caso de uso requiere saber qué se borró (por ejemplo, para cumplimiento regulatorio o para mantener consistencia con el origen), incremental por cursor no alcanza. Necesitás CDC o full refresh.
La escritura también importa
El mecanismo de extracción va de la mano con cómo escribís en destino:
- Replace: borrás todo y escribís de nuevo. Natural para full refresh.
- Append: agregás registros nuevos. Funciona para eventos inmutables (logs, sensores, transacciones).
- Merge (upsert): si el registro existe lo actualizás, si no lo insertás. Natural para incremental cuando los registros pueden modificarse.
La combinación tiene que tener sentido. Si hacés extracción incremental y append en destino, vas a duplicar registros cada vez que un registro se modifique y vuelva a entrar en tu ventana de extracción.
En resumen
Full, incremental y CDC no son tres niveles de sofisticación donde CDC es "mejor". Son tres mecanismos con presupuestos distintos sobre cuánto podés confiar en el origen.
Full refresh asume menos sobre el origen y por eso reduce el riesgo de perder cambios (pero es caro). Incremental asume que el origen te dice la verdad sobre qué cambió (y si no lo hace, perdés datos). CDC lee el log de transacciones y captura todo (pero requiere más infraestructura).
Elegí el mecanismo que se ajuste a tu nivel de control sobre el origen, no el que parezca más eficiente en el diagrama.