Blog DevOps Data Git Bases de datos CI/CD SQL Cloud

Por qué tu esquema de base de datos debe estar en Git

Diagrama de un esquema de base de datos gestionado mediante control de versiones en Git

Introducción

Durante años, muchas organizaciones han tratado el esquema de la base de datos como algo separado del código de aplicación: cambios aplicados manualmente, scripts compartidos por correo o documentación que no siempre refleja el estado real del entorno. Ese enfoque puede funcionar en proyectos pequeños, pero se vuelve frágil cuando aparecen varios equipos, varios entornos y despliegues frecuentes.

Versionar el esquema de la base de datos en Git ayuda a aplicar al modelo de datos las mismas prácticas que ya se consideran normales en el desarrollo de software: historial de cambios, revisión por pares, automatización, trazabilidad y capacidad de reproducir entornos.

La idea central es sencilla: si un cambio en una tabla, índice, vista, procedimiento almacenado o restricción puede afectar a la aplicación, debería estar sujeto al mismo nivel de control que el código que consume esos objetos.

Qué significa versionar un esquema de base de datos

Versionar un esquema no consiste solo en guardar un volcado ocasional de la base de datos. Un enfoque útil suele incluir, al menos, una de estas formas de representación:

  • Scripts SQL con cambios incrementales.
  • Proyectos de base de datos que describen el estado esperado del esquema.
  • Migraciones gestionadas por herramientas especializadas.
  • Scripts de validación, pruebas o datos de referencia necesarios para comprobar el cambio.

Lo importante es que el repositorio permita responder preguntas básicas:

  • Qué cambió en el esquema.
  • Quién propuso el cambio.
  • Por qué se hizo.
  • En qué revisión se introdujo.
  • Cómo se despliega o revierte, cuando sea posible.
  • Qué impacto tiene sobre aplicaciones, informes, integraciones o procesos analíticos.

Git no sustituye a una estrategia de migraciones, copias de seguridad o gobierno de datos, pero sí proporciona una base común para coordinar el cambio.

Beneficios de tener el esquema en Git

Trazabilidad y auditoría

Cada cambio queda asociado a un commit, una rama, una revisión y, si se trabaja con pull requests, una conversación técnica. Esto mejora la trazabilidad frente a cambios manuales aplicados directamente sobre un entorno.

En sectores regulados, esta trazabilidad puede ser especialmente útil porque permite conservar evidencia de:

  • La motivación del cambio.
  • La persona o equipo que lo propuso.
  • Las revisiones realizadas.
  • Las pruebas o validaciones asociadas.
  • El momento en el que el cambio entró en una rama determinada.

Conviene matizar que Git por sí solo no garantiza cumplimiento normativo. Para auditorías formales también suelen ser necesarios controles de acceso, segregación de funciones, registros de despliegue, políticas de aprobación y evidencias operativas.

Colaboración entre equipos

Los cambios de esquema suelen impactar a más de un perfil: desarrolladores backend, equipos de datos, responsables de reporting, administradores de base de datos y arquitectos. Gestionarlos en Git permite revisar las modificaciones antes de que lleguen a entornos compartidos.

Por ejemplo, una pull request puede mostrar que una nueva columna es obligatoria, que se elimina un índice o que una tabla cambia de nombre. Esa revisión temprana ayuda a detectar problemas antes del despliegue:

  • Consultas que dejarían de funcionar.
  • Cambios incompatibles con versiones anteriores de la aplicación.
  • Índices redundantes o potencialmente costosos.
  • Restricciones que podrían fallar con datos existentes.
  • Cambios que requieren una migración de datos, no solo de estructura.

Automatización de despliegues

Cuando el esquema está en Git, puede formar parte de un pipeline de integración y entrega continua. Esto permite automatizar validaciones como:

  • Compilación o análisis sintáctico de scripts.
  • Ejecución de migraciones en un entorno temporal.
  • Pruebas de integración contra una base de datos de prueba.
  • Comparación entre el esquema esperado y el esquema desplegado.
  • Revisión de cambios potencialmente destructivos.

La automatización reduce la dependencia de pasos manuales, aunque no elimina la necesidad de aprobaciones en entornos críticos. En bases de datos productivas, especialmente con grandes volúmenes de datos, un cambio correcto desde el punto de vista sintáctico puede seguir siendo riesgoso por bloqueo de tablas, tiempos de ejecución, impacto en índices o compatibilidad con aplicaciones existentes.

Reproducibilidad de entornos

Un repositorio bien mantenido facilita crear entornos de desarrollo, pruebas o integración con un esquema consistente. Esto evita que cada desarrollador trabaje contra una base de datos ligeramente distinta o que los errores aparezcan solo al llegar a un entorno compartido.

La reproducibilidad es especialmente importante cuando se trabaja con:

  • Microservicios con bases de datos independientes.
  • Aplicaciones con ciclos de despliegue frecuentes.
  • Equipos distribuidos.
  • Entornos efímeros para pruebas automatizadas.
  • Plataformas cloud donde la infraestructura puede recrearse bajo demanda.

Enfoques habituales

No existe una única forma correcta de versionar esquemas. La elección depende del motor de base de datos, del tamaño del equipo, del tipo de aplicación y del nivel de automatización deseado.

Scripts SQL incrementales

Un enfoque común consiste en guardar scripts ordenados que representan cambios incrementales. Cada script describe una modificación concreta del esquema.

-- V001__create_users_table.sql
CREATE TABLE dbo.Users (
    UserID INT NOT NULL PRIMARY KEY,
    UserName NVARCHAR(100) NOT NULL,
    Email NVARCHAR(256) NOT NULL
);
GO

CREATE UNIQUE INDEX IX_Users_Email
ON dbo.Users (Email);
GO

Un segundo cambio podría añadirse en otro archivo:

-- V002__add_created_at_to_users.sql
ALTER TABLE dbo.Users
ADD CreatedAt DATETIME2 NOT NULL
    CONSTRAINT DF_Users_CreatedAt DEFAULT SYSUTCDATETIME();
GO

Este enfoque es fácil de entender y funciona bien cuando el equipo mantiene una disciplina clara: scripts inmutables una vez aplicados, orden consistente, revisión obligatoria y pruebas antes de producción.

El riesgo aparece cuando se editan scripts antiguos que ya se han ejecutado en otros entornos. En la mayoría de estrategias basadas en migraciones, un cambio ya aplicado no debería modificarse; se crea una nueva migración que lleva el esquema desde el estado anterior al nuevo.

Herramientas de migración

Herramientas como Flyway o Liquibase permiten gestionar cambios incrementales, registrar qué migraciones se han aplicado y ejecutarlas en orden. Son especialmente útiles cuando se trabaja con varios entornos y se quiere evitar depender de ejecución manual.

Una estructura típica puede ser:

db/
  migrations/
    V001__create_users_table.sql
    V002__add_created_at_to_users.sql
    V003__create_orders_table.sql

El pipeline o proceso de despliegue ejecuta las migraciones pendientes contra el entorno correspondiente. La herramienta mantiene una tabla de metadatos para saber qué scripts ya se aplicaron.

Este modelo ayuda a controlar la evolución del esquema, pero no elimina la responsabilidad de diseñar migraciones seguras. Por ejemplo, eliminar una columna usada por una versión anterior de la aplicación puede requerir un despliegue en varias fases:

  1. Añadir el nuevo elemento sin romper compatibilidad.
  2. Actualizar la aplicación para usarlo.
  3. Migrar datos si corresponde.
  4. Retirar el elemento antiguo cuando ya no haya dependencias.

Proyectos de base de datos

En ecosistemas SQL Server y Azure SQL, también es habitual trabajar con proyectos de base de datos que describen el estado deseado del esquema y permiten generar artefactos de despliegue. Este enfoque puede encajar bien cuando el equipo quiere revisar objetos de base de datos como código fuente: tablas, vistas, procedimientos, funciones, tipos o permisos.

La ventaja de este modelo es que facilita razonar sobre el esquema completo. La precaución principal es revisar cuidadosamente el script de despliegue generado antes de aplicarlo en entornos sensibles, sobre todo si incluye operaciones destructivas o cambios con impacto sobre datos existentes.

Infraestructura como código y límites del enfoque

Herramientas de infraestructura como código pueden definir recursos cloud relacionados con bases de datos: servidores, instancias, bases de datos, redes, parámetros de capacidad o configuraciones de seguridad. Sin embargo, no siempre son la mejor herramienta para describir cambios finos del esquema interno, como columnas, índices o procedimientos almacenados.

Por ejemplo, definir una base de datos gestionada como recurso de infraestructura no equivale a versionar todas sus tablas:

resource "azurerm_mssql_database" "example" {
  name      = "example-db"
  server_id = azurerm_mssql_server.example.id
  collation = "SQL_Latin1_General_CP1_CI_AS"
}

Este tipo de definición puede ser útil para crear o configurar la base de datos como recurso cloud, pero el modelo relacional interno suele gestionarse mejor con scripts SQL, proyectos de base de datos o herramientas de migración.

Buenas prácticas

1. Separar cambios de esquema y datos

No todos los cambios son iguales. Conviene distinguir entre:

  • Cambios estructurales: tablas, columnas, claves, índices, vistas.
  • Cambios de datos de referencia: catálogos, códigos, configuraciones.
  • Migraciones de datos: transformaciones o movimientos de información existente.
  • Cambios operativos: permisos, usuarios, roles, parámetros de entorno.

Mezclarlos sin criterio dificulta la revisión y aumenta el riesgo de errores. En muchos equipos es preferible que cada migración tenga un propósito claro y verificable.

2. Evitar cambios destructivos directos

Operaciones como DROP TABLE, DROP COLUMN o cambios de tipo de datos pueden ser necesarias, pero deberían tratarse con especial cuidado. Antes de aplicarlas, conviene comprobar:

  • Si hay aplicaciones o informes que dependen del objeto.
  • Si existen datos que deben conservarse.
  • Si el cambio puede bloquear tablas durante demasiado tiempo.
  • Si hay una estrategia de rollback o mitigación.
  • Si el despliegue debe dividirse en fases.

En sistemas con alta disponibilidad, muchas migraciones se diseñan para ser compatibles hacia delante y hacia atrás durante un periodo de transición.

3. Revisar los cambios mediante pull requests

Los cambios de base de datos no deberían entrar directamente en la rama principal sin revisión. Una pull request permite evaluar:

  • Calidad del diseño.
  • Convenciones de nombres.
  • Impacto en rendimiento.
  • Compatibilidad con versiones anteriores.
  • Seguridad y permisos.
  • Necesidad de índices o restricciones adicionales.

La revisión debe incluir a las personas adecuadas. En algunos equipos será un DBA; en otros, un arquitecto de datos, un responsable de plataforma o el equipo propietario del servicio.

4. Probar migraciones en entornos representativos

Una migración que funciona en una base de datos vacía puede fallar en una base de datos con millones de filas, restricciones existentes o datos inconsistentes. Siempre que sea posible, las migraciones deberían probarse en entornos que representen razonablemente la realidad de producción.

Algunas validaciones útiles son:

  • Ejecutar la migración desde una versión anterior realista del esquema.
  • Medir tiempos de ejecución.
  • Comprobar bloqueos o impacto transaccional.
  • Validar consultas críticas después del cambio.
  • Verificar que las migraciones son idempotentes solo cuando se diseñen explícitamente para ello.

5. No guardar secretos en el repositorio

Los scripts y pipelines no deberían incluir contraseñas, cadenas de conexión completas, claves o tokens. Las credenciales deben gestionarse mediante mecanismos seguros del entorno de despliegue, como variables protegidas, identidades administradas o almacenes de secretos.

Esto es especialmente importante cuando el repositorio es compartido por varios equipos o cuando existe automatización de CI/CD.

6. Documentar decisiones relevantes

No todo cabe en el SQL. Algunas decisiones de diseño merecen explicación adicional:

  • Por qué se eligió una clave natural o surrogate key.
  • Por qué se añadió un índice concreto.
  • Qué compatibilidad se mantiene con versiones anteriores.
  • Qué supuestos existen sobre volumen de datos.
  • Qué pasos manuales, si los hay, requiere la operación.

Esa documentación puede vivir en la descripción de la pull request, en comentarios del script o en archivos Markdown del repositorio.

Integración con CI/CD

Un pipeline de CI/CD para esquemas de base de datos no tiene por qué aplicar cambios directamente en producción. De hecho, en muchos entornos lo más prudente es separar validación, generación de artefactos y despliegue.

Un flujo razonable puede ser:

  1. Un desarrollador propone un cambio de esquema en una rama.
  2. El pipeline valida los scripts o el proyecto de base de datos.
  3. Se crea una base de datos temporal o de integración.
  4. Se aplican las migraciones.
  5. Se ejecutan pruebas automatizadas.
  6. La pull request se revisa y aprueba.
  7. El despliegue a entornos superiores se realiza con aprobaciones y controles adicionales.

Un ejemplo simplificado de pipeline podría limitarse a validar y ejecutar migraciones en un entorno de prueba. La instalación concreta de herramientas y la gestión de credenciales dependerán de la plataforma usada:

trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

steps:
  - checkout: self

  - script: |
      flyway migrate
    displayName: 'Ejecutar migraciones en entorno de prueba'
    env:
      FLYWAY_URL: $(FLYWAY_URL)
      FLYWAY_USER: $(FLYWAY_USER)
      FLYWAY_PASSWORD: $(FLYWAY_PASSWORD)

Este ejemplo asume que la herramienta está disponible en el agente o se instala en un paso previo controlado por el equipo. En un pipeline real, las credenciales deberían almacenarse como secretos y el despliegue a producción debería incluir aprobaciones, ventanas de cambio o validaciones adicionales según el riesgo.

Consideraciones específicas en cloud

En Azure y otras plataformas cloud, versionar el esquema en Git encaja de forma natural con prácticas de DevOps, pero conviene no confundir capas:

  • La infraestructura define dónde se ejecuta la base de datos.
  • La configuración define cómo se protege y opera.
  • El esquema define la estructura lógica de los datos.
  • Los pipelines coordinan la validación y el despliegue.

Para servicios como Azure SQL Database, por ejemplo, es habitual combinar:

  • Repositorios Git para scripts o proyectos de base de datos.
  • Pipelines para validación y despliegue.
  • Controles de identidad y permisos.
  • Reglas de red y seguridad gestionadas fuera del esquema.
  • Monitorización del rendimiento y errores después del despliegue.

El objetivo no es automatizar por automatizar, sino reducir cambios manuales no trazables y aumentar la confianza en cada modificación.

Errores frecuentes

Tratar producción como fuente de verdad única

Si la única forma de saber cómo es el esquema real es conectarse a producción, el equipo tiene un problema de trazabilidad. Producción debe reflejar un estado desplegado y controlado, no ser el lugar donde se diseñan cambios manualmente.

Guardar scripts sin orden ni convención

Un directorio lleno de archivos SQL sin numeración, fecha, propósito o relación clara con versiones es difícil de mantener. La convención de nombres no es un detalle menor: ayuda a entender el orden y la intención de cada cambio.

No revisar el impacto en datos existentes

Añadir una columna NOT NULL, cambiar un tipo de dato o crear una clave única puede fallar si los datos actuales no cumplen la nueva regla. Las migraciones deben considerar el estado real de la información, no solo el diseño ideal.

Ejecutar automáticamente todo en producción

La automatización no debe eliminar el juicio técnico. Algunos cambios pueden desplegarse de forma continua con bajo riesgo; otros requieren revisión manual, pruebas de carga, coordinación con equipos consumidores o un plan de reversión.

Conclusión

El esquema de una base de datos forma parte del producto. Si cambia sin control, puede romper aplicaciones, informes, integraciones y procesos de negocio. Por eso tiene sentido gestionarlo en Git junto con el resto del código y los artefactos técnicos.

Versionar el esquema aporta trazabilidad, facilita la colaboración y abre la puerta a validaciones automatizadas. Pero la práctica debe ir acompañada de buenas decisiones: migraciones revisadas, pruebas en entornos representativos, gestión segura de credenciales y cautela ante cambios destructivos.

La recomendación no es convertir la base de datos en un conjunto de scripts sin gobierno, sino integrarla en el ciclo de vida del software. Cuando el esquema está en Git, los cambios dejan de ser operaciones aisladas y pasan a ser parte de un proceso revisable, repetible y más seguro.