El Arte de Tocar la Base de Datos en Producción sin Despertar al Monstruo
Aprende a migrar y refactorizar esquemas de bases de datos en producción sin causar downtime ni pérdida de datos. Una guía práctica y probada en batalla, basada en años de experiencia y algunos sustos.
Tocar la base de datos en producción es uno de esos momentos que separa a los juniors de los seniors. No por la habilidad técnica, sino por el nivel de pánico controlado que eres capaz de manejar. Todos hemos estado ahí: con el cursor parpadeando sobre un ALTER TABLE en una base de datos con millones de registros, sudando frío y rezando a todos los dioses de la computación.
He roto cosas. He pasado noches en vela arreglando desaguisados. Pero también he aprendido a hacerlo bien. Y la clave no es ser un vaquero intrépido, sino un ingeniero metódico y paranoico.
El Miedo es Real (y Justificado)
Una migración de esquema mal ejecutada puede causar:
- Downtime: La aplicación deja de funcionar porque el código no coincide con la estructura de la base de datos.
- Corrupción de datos: El peor de los escenarios. Datos que se pierden o se vuelven inconsistentes.
- Degradación del rendimiento: Un nuevo índice mal pensado o un
ALTERque bloquea una tabla durante horas.
El objetivo no es eliminar el miedo, es usarlo para planificar meticulosamente.
La Filosofía: Cero Downtime, Cero Sorpresas
La regla de oro es simple: los cambios destructivos están prohibidos en un solo paso. Olvídate de renombrar una columna o cambiar su tipo directamente en producción. Eso es una receta para el desastre. En su lugar, adoptamos una estrategia de múltiples fases, segura y reversible.
El Plan de Batalla: La Estrategia de Expansión y Contracción
Este método es tu mejor amigo. Se basa en la idea de que siempre debes mantener tu aplicación funcionando, incluso en medio de un cambio de esquema. Consta de tres fases:
Fase 1: Expansión (Añadir, no quitar)
Nunca modifiques o elimines nada existente en este paso. Solo añade.
Ejemplo: Queremos dividir una columna full_name en first_name y last_name.
-
Añade las nuevas columnas: Ejecutas una migración para añadir
first_nameylast_namea tu tabla de usuarios. Ambas deben serNULLABLEpor ahora. La columnafull_nameno se toca.ALTER TABLE users ADD COLUMN first_name VARCHAR(255) NULL; ALTER TABLE users ADD COLUMN last_name VARCHAR(255) NULL; -
Despliega el código que escribe en ambos sitios: Modifica tu aplicación para que, al crear o actualizar un usuario, escriba tanto en la vieja columna
full_namecomo en las nuevasfirst_nameylast_name. Para leer, la aplicación todavía priorizafull_namesi las nuevas columnas están vacías. Esto garantiza que el sistema siga funcionando sin interrupciones.
Fase 2: Migración (El Llenado de Datos)
Ahora que tu aplicación ya maneja las nuevas columnas para datos nuevos, necesitas rellenar los datos de los registros existentes.
-
Ejecuta un script de backfill: Crea un script (no una migración SQL) que lea los registros antiguos uno por uno (o en lotes pequeños para no sobrecargar la base de datos). Para cada registro, extrae el
full_name, lo divide enfirst_nameylast_name, y actualiza las nuevas columnas.Pro-tip: Hazlo en segundo plano y de forma gradual. No intentes actualizar 10 millones de filas de golpe.
-
Verifica la migración: Una vez que el script termina, comprueba que todos los registros tengan sus nuevas columnas pobladas. Puedes ejecutar consultas para encontrar filas donde
first_nameseaNULLperofull_nameno lo sea.
Fase 3: Contracción (La Limpieza Final)
Solo cuando estás 100% seguro de que todos los datos están migrados y que tu código ya no depende de la columna antigua, puedes empezar a limpiar.
-
Cambia el código para usar solo lo nuevo: Modifica tu aplicación para que lea y escriba únicamente en
first_nameylast_name. El código que interactuaba confull_namese elimina. -
Despliega este nuevo código. Monitorea de cerca para asegurarte de que no hay errores. Tu aplicación ahora ignora por completo la columna
full_name. -
Elimina la columna antigua: Después de un tiempo prudencial (un día, una semana, lo que te dé tranquilidad), ejecuta la migración final para eliminar la columna
full_name.ALTER TABLE users DROP COLUMN full_name;
¡Listo! Has refactorizado tu esquema en producción sin que tus usuarios se dieran cuenta.
Herramientas y Prácticas que te Salvarán la Piel
-
Migrations como Código: Usa siempre una herramienta de migración (Flyway, Liquibase, o las integradas en frameworks como Django, Rails, Laravel). Las migraciones deben estar versionadas en tu repositorio de código. Nunca ejecutes SQL manual en producción.
-
Backups, Backups y más Backups: Antes de tocar nada, haz un backup. ¿Ya lo hiciste? Compruébalo. Haz otro si es necesario. Un backup verificado es tu única red de seguridad real.
-
Prueba en Staging: Ten un entorno de
stagingcon una copia (anonimizada si es necesario) de la base de datos de producción. Prueba todo el proceso ahí, midiendo tiempos y posibles bloqueos. -
Feature Flags: Para cambios grandes, usa feature flags. Te permiten activar o desactivar el nuevo código (el que usa el nuevo esquema) para un porcentaje de usuarios, o solo para administradores. Si algo va mal, apagas el flag y el sistema vuelve al código antiguo al instante.
-
Monitoreo Constante: Durante y después del despliegue, tus ojos deben estar pegados a tus dashboards de monitoreo: uso de CPU de la base de datos, latencia de consultas, tasa de errores de la aplicación, etc.
Cambiar un esquema en producción siempre dará respeto. Pero con un plan sólido, las herramientas adecuadas y una dosis saludable de paranoia, puedes pasar de sudar frío a sentir la satisfacción de una cirugía a corazón abierto ejecutada a la perfección.
Preguntas frecuentes
¿Por qué no deberías hacer cambios destructivos en un solo paso?
Porque modificar o renombrar columnas directamente puede provocar caídas del servicio, corrupción de datos o bloqueos de tablas que degraden el rendimiento. Para evitar sorpresas, debes aplicar una estrategia en varias fases que sea segura y reversible.
¿Cómo debes rellenar las nuevas columnas con los datos ya existentes?
Debes utilizar un script de backfill en segundo plano que actualice los registros gradualmente o en lotes pequeños para evitar sobrecargar la base de datos. Una vez termine, verifica mediante consultas que ningún registro se haya quedado sin migrar.
¿Cuándo es seguro eliminar de forma definitiva la columna antigua?
Solo puedes hacerlo cuando verifiques al 100 % que todos los datos se han migrado y tras desplegar código que ignore por completo dicha columna. Además, es recomendable dejar pasar un tiempo prudencial antes de ejecutar la eliminación en la base de datos.
¿Qué beneficio obtienes al usar feature flags en estos cambios?
Te permiten activar el código asociado al nuevo esquema de forma gradual para un porcentaje de usuarios o administradores. Si surge algún fallo imprevisto, puedes apagar el flag de inmediato para que el sistema regrese al código anterior.