Saltar al contenido principal
Volver a todos los artículos
Bases de Datos5 min de lectura

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 `ALTER` que 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`.

1. Añade las nuevas columnas: Ejecutas una migración para añadir `first_name` y `last_name` a tu tabla de usuarios. Ambas deben ser `NULLABLE` por ahora. La columna `full_name` no se toca.


    ALTER TABLE users ADD COLUMN first_name VARCHAR(255) NULL;
    ALTER TABLE users ADD COLUMN last_name VARCHAR(255) NULL;
    

2. 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_name` como en las nuevas `first_name` y `last_name`. Para leer, la aplicación todavía prioriza `full_name` si 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.

1. 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 en `first_name` y `last_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.

2. 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_name` sea `NULL` pero `full_name` no 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.

1. Cambia el código para usar solo lo nuevo: Modifica tu aplicación para que lea y escriba únicamente en `first_name` y `last_name`. El código que interactuaba con `full_name` se elimina.

2. 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`.

3. 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 `staging` con 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.

Escrito por Samuel Moreno

Socio y Desarrollador en Sinergia Barcelona.