Migrar una base de datos a Postgres gestionado en la nube suena, sobre el papel, casi elegante. AWS RDS, Azure Database for PostgreSQL, Google Cloud SQL… todos prometen lo mismo: menos operación, más disponibilidad, backups gestionados, escalado más sencillo y una migración “sin apenas impacto”. Y muchas veces es verdad. Pero hay una parte que no sale en la diapositiva comercial: una migración puede terminar “correctamente” y aun así estar mal. Puede faltar una tabla pequeña que nadie miró. Puede haberse quedado una secuencia por debajo del último id. Puede haber diferencias de esquema entre origen y destino. Puede que una réplica estuviera “casi” al día, pero ese “casi” incluya transacciones confirmadas. Puede que el rendimiento parezca aceptable en vacío y se hunda el lunes a las 9:20. Por eso una migración segura no es la que termina rápido. Es la que puedes demostrar. No basta con que la herramienta diga “success”. Hay que poder decir: estos eran los datos antes, estos son los datos después, estas son las diferencias esperadas, estas son las pruebas realizadas y este es el plan real si hay que volver atrás. 1. Antes del corte: saber exactamente qué tienes La migración no empieza cuando apuntas la aplicación al nuevo endpoint. Empieza bastante antes, con una foto seria del origen. Lo primero es sacar un inventario del esquema. Un pg_dump --schema-only de producción, versionado en Git, te da una referencia objetiva. Tablas, índices, constraints, funciones, vistas, triggers, extensiones, roles y permisos relevantes. Si algo cambia después, ya no es “una sorpresa”: es deriva. También necesitas una línea base de datos. No siempre puedes hacer count(*) de todo alegremente en una base grande en producción, pero sí puedes definir una estrategia razonable: - Conteos exactos en tablas pequeñas y medianas. - Conteos por partición en tablas grandes. - min, max, sum o hashes sobre claves primarias cuando tenga sentido. - Checksums calculados por rangos de clave o ventanas temporales. - Captura de secuencias y últimos valores. - Registro del LSN de origen con pg_current_wal_lsn(). La idea no es hacer magia. La idea es tener algo contra lo que comparar. Sin línea base, cualquier verificación posterior se convierte en un acto de fe con comandos bonitos. Y la fe, en migraciones de datos, factura caro. 2. Elegir la herramienta sin enamorarse de ella pg_dump y pg_restore siguen siendo una opción muy sólida para migraciones frías o semi-frías. Si puedes permitir una ventana de parada clara, probablemente sea el camino más simple, auditable y fácil de repetir. Para migraciones en caliente entran en juego otras opciones: replicación lógica nativa, pglogical, herramientas CDC como Debezium, servicios cloud de migración o soluciones comerciales. Todas sirven, pero ninguna te exime de verificar. Cada herramienta tiene sus bordes. Con pg_dump / pg_restore, conviene usar formato directory y paralelismo: pg_dump --format=directory --jobs=4 --file=backup_dir origen pg_restore --jobs=4 --dbname=destino backup_dir
Después, pg_restore --list permite revisar el manifiesto de objetos restaurados. No es glamuroso, pero es muy útil. Con replicación lógica, la obsesión debe ser el lag. El momento seguro de corte no es “cuando parece que ya está”. Es cuando sabes sobre qué LSN estás cortando y puedes demostrar que destino ha aplicado lo necesario. Con CDC, cuidado con los tipos, las operaciones DDL, los cambios de esquema durante la migración y las tablas sin clave primaria. Todo lo que sea “caso especial” debe estar escrito antes del día D, no descubierto con usuarios dentro. 3. El corte: menos épica y más runbook El día de la migración no es para improvisar. Es para ejecutar un guion. Un buen runbook debería decir, paso a paso: 1. Quién congela despliegues. 2. Quién pone la aplicación en modo mantenimiento si hace falta. 3. Qué comando captura el último LSN. 4. Cómo se comprueba el lag. 5. Qué validaciones bloquean el avance. 6. Quién cambia DNS, variables de entorno o secretos. 7. Qué pruebas funcionales se ejecutan. 8. Cuándo se declara éxito. 9. Cuándo se declara rollback. Esto parece burocracia hasta que algo falla. Entonces deja de parecer burocracia y se convierte en oxígeno. La regla sencilla: si no puedes explicar cómo vuelves atrás, todavía no estás listo para avanzar. 4. Después del corte: comparar, no mirar de reojo Una vez la aplicación apunta al nuevo Postgres, empieza la parte importante: demostrar que los datos están bien. Hay que hacer comparación tabla a tabla. No solo una muestra. No solo “las tablas grandes parecen tener el mismo tamaño”. Comparación real. Dependiendo del volumen, puedes usar herramientas como data-diff, scripts propios por particiones o queries de agregación controladas. Lo importante es comparar con método: - Número de filas por tabla. - Número de filas por partición o rango. - Mínimos y máximos de claves. - Checksums por bloques lógicos. - Secuencias. - Constraints. - Índices. - Extensiones. - Permisos. - Vistas y funciones críticas. Especial atención a las secuencias. Es el clásico error tonto que no parece grave hasta que la primera inserción real intenta reutilizar un id. Ejemplo conceptual: SELECT setval('mi_tabla_id_seq', (SELECT max(id) FROM mi_tabla));
No lo hagas a mano tabla por tabla si tienes muchas. Automatízalo, revísalo y deja evidencia. También hay que validar constraints. Si el origen llevaba años tolerando datos raros, la migración puede ser el primer momento en el que alguien descubre claves huérfanas, checks rotos o supuestos que nunca fueron verdad. 5. Rendimiento: que arranque no significa que aguante Que la aplicación funcione después del corte no significa que la migración haya terminado. Postgres gestionado en cloud tiene límites distintos: IOPS, throughput, latencia de almacenamiento, comportamiento de burst, parámetros gestionados, autovacuum, backups, réplicas, extensiones permitidas y restricciones del proveedor. Antes y después del corte conviene comparar las consultas críticas: EXPLAIN (ANALYZE, BUFFERS) SELECT ...
Las 20 consultas principales de pg_stat_statements son un buen punto de partida. Si una consulta cambia de plan, hay que entender por qué. Puede ser por estadísticas obsoletas, diferencias de versión, parámetros distintos, extensiones ausentes o simplemente porque el almacenamiento cloud no se comporta igual que el entorno anterior. Después del restore, ANALYZE no es opcional. Es parte de la migración. En algunos casos también tiene sentido reconstruir índices, especialmente si vienes de una base con mucho histórico, bloat o mantenimiento irregular. No siempre hay que lanzar un REINDEX DATABASE a lo bruto, pero sí revisar índices críticos y bloat. 6. Rollback: si no está probado, no existe Todo el mundo tiene rollback hasta que tiene que usarlo. Una migración seria define una ventana de vuelta atrás: 24 horas, 48 horas, 72 horas, una semana. Lo que tenga sentido para el negocio. Durante esa ventana debe estar claro qué pasa con las escrituras nuevas. Este punto es incómodo, porque el rollback no es solo técnico. Es una decisión de datos. Si después del corte los usuarios escriben en el nuevo sistema, volver al origen antiguo implica reconciliar esas escrituras o perderlas. Por eso hay que decidir antes: - ¿El origen queda en solo lectura? - ¿Se mantiene replicación inversa? - ¿Se acepta una ventana sin rollback limpio? - ¿Qué datos se perderían si se vuelve atrás? - ¿Quién autoriza esa decisión? pg_rewind puede ser útil en determinados escenarios de failback físico, pero no es una varita universal para cualquier migración gestionada o lógica. Hay que probarlo en staging con una topología parecida a la real. Si no se ha probado, no forma parte del plan. Es solo una esperanza con nombre de comando. 7. Observabilidad: las semanas posteriores también cuentan La migración no acaba cuando se apaga la videollamada del día D. Durante los días siguientes hay que vigilar: - Errores de aplicación. - Latencia de queries. - Saturación de conexiones. - Uso de WAL. - Autovacuum. - Locks. - Replicación, si existe. - Crecimiento anómalo de tablas o índices. - Fallos de backup. - Diferencias en jobs programados. - Permisos y roles usados por procesos batch. Muchas migraciones fallan de forma silenciosa. No explotan. Se van torciendo. Y eso es peor, porque cuando alguien se da cuenta ya no estás en ventana de rollback, los backups han rotado y el origen antiguo ya parece arqueología. Qué deberías hacer mañana Si estás preparando una migración a Postgres gestionado, mañana no empieces por abrir la consola cloud. Empieza por demostrar que conoces tu base. 1. Genera un inventario de esquema con pg_dump --schema-only y guárdalo versionado. 2. Define tus 20 tablas críticas y calcula conteos, rangos y hashes por partición o por clave. 3. Monta un staging lo más parecido posible al destino real. 4. Haz un restore completo y mide cuánto tarda de verdad. 5. Ejecuta un data-diff serio entre origen y destino. 6. Valida secuencias, constraints, extensiones, roles y permisos. 7. Captura las consultas críticas con pg_stat_statements. 8. Prueba el runbook de corte. 9. Prueba el rollback, no lo escribas solo en una página bonita. 10. Pide al proveedor los límites reales de IOPS, throughput, conexiones, backups y ventanas de mantenimiento. Migrar a Postgres gestionado puede ser una muy buena decisión. Menos operación, más foco, mejor disponibilidad y un camino más limpio para escalar. Pero la seguridad no viene incluida por defecto. La seguridad aparece cuando puedes mirar a negocio, a auditoría o a tu propio equipo y decir: “Estos eran los datos antes. Estos son los datos después. Esto es lo que hemos comparado. Esto es lo que no ha cambiado. Y si algo falla, sabemos exactamente cómo volver.” Eso es una migración segura. No la que acaba rápido. La que deja pruebas.
¿Reconoces este problema en tu empresa? Compártelo en LinkedIn
Compartir en LinkedIn¿Tu migración pasa la prueba de la suma de verificación?
En Assets Consultores validamos la integridad de tus datos antes, durante y después del corte.