Estrategias para versionar las bases de datos relacionales

Después de que la semana pasada diéramos los primeros pasos a la hora de versionar las bases de datos, esta semana me gustaría hablar de dos de las estrategias de versionado de bases de datos que más he visto utilizar en las empresas: versionado a través de incrementales (o actualizaciones), y versionado de un único fichero con el esquema de la base de datos (o versionado del estado final de la base de datos).
También hay otro enfoque, que no vamos a tratar, y es que existen herramientas ORM (Object Relational Mapping), como por ejemplo Entity Framework, Hibernate ORM que generan los cambios de base de datos a partir de los cambios en el código.
Antes de empezar, recuerda que para implementar cualquiera de estas estrategias que vamos a comentar ahora utilizaremos siempre el control de versiones, versionando a la par código y base de datos.
Además comenzaremos a versionar la base de datos a partir de una línea base de base de datos (un fichero o ficheros con los scripts necesarios para recrear la base de datos inicial) que subiremos a nuestra herramienta de control de versiones, en alguna carpeta destinada a scripts de base de datos dentro de nuestro proyecto software.
Digo fichero o ficheros, porque podemos optar por tener un único fichero línea base de toda nuestra base de datos con todos los scripts necesarios o crear una línea base por cada uno de los objetos de nuestra base de datos (tablas,vistas etc) como puedes ver a continuación.
versioningDatabases
¡Veamos las estrategias!

Versionado a través de scripts incrementales o actualizaciones

En esta estrategia, tomando como referencia la línea base de base de datos, cada vez que queramos hacer un cambio en ella, crear nuevas tablas, modificarlas etc, crearemos un fichero con los scripts necesarios y lo subiremos a la carpeta correspondiente en el control de versiones.
Nombraremos cada fichero de scripts con un identificador que acordaremos previamente, que puede tener una fecha, un timestamp y una pequeño texto que describa lo que hace el script.
Esta nomenclatura tendrá que reflejar el orden en el que se deben aplicar los scripts.
Un ejemplo podría ser:

0001 – 2014_11_06 – Create users table.sql

Normalmente no crearemos un fichero por cada pequeña modificación de base de datos, sino que si por ejemplo un desarrollador está programando una historia de usuario, y ésta necesita hacer varios cambios de base de datos, todos esos cambios correspondientes a esa historia de usuario irán en un mismo fichero.
Así nuestra carpeta de scripts se convertirá en algo parecido a lo siguiente:

0000 – 2014_11_06 – Baseline.sql

0001 – 2014_11_06 – Create users table.sql

0002 – 2014_11_07 – Add registration date fields to users.sql

Este enfoque es como fueramos realizando pequeños cambios a partir de la línea base.
En otras palabras, cuando los desarrolladores se bajan los últimos cambios del control de versiones, no reciben la última versión de la base de datos, o de los objetos que la forman, sino una serie de scripts que deben ejecutar en el orden correcto para pasar de un estado de base de datos a otro.
Si en el ejemplo quisierámos recrear la base de datos de la versión del 7 de noviembre, tendríamos que lanzar los scrips de la línea base de base de datos, el script Create users table, y Add registration date fields to users.
Aquí es muy importante que el equipo sepa qué scripts se han pasado en cada entorno y aplicar aquellos scripts que no han ejecutado (recuerda lo que comentamos en el post pasado de crear una tabla de versiones en cada base de datos.)

Ventajas:

– Seremos capaces de ver a simple vista todos los cambios que se han ido produciendo, de forma individual.

– Podremos ejecutar todos los scripts siguiendo el orden indicado para crear la base de datos final.

– Es sencillo y rápido almacenar qué scripts se han ido pasando en qué entorno y cuáles faltan por ejecutar.

– Este enfoque vale para cualquier entorno, desde desarrollo a producción, ya que vamos evolucionando la base de datos poco a poco, incrementalmente.

Desventajas:

– No tenemos una visión general de qué pinta tiene el esquema de base de datos en cualquier punto del tiempo, y las diferencias entre versiones. Solo tendremos dicha visión al pasar los scripts necesarios en el entorno correspondiente.

– Si queremos montar un entorno, creando la base de datos desde cero, tendremos que ejecutar todos los scripts en orden.

– Si la base de datos no está en el estado inicial que esperabas al crear el script, los scripts no harán efecto.Es muy importante que los scripts se ejecuten siguiendo el proceso de versionado (por ejemplo tenemos que evitar que alguien ejecute algún script sin actualizar la tabla de versionado de la base de datos)

– Hay que acordar una buena numeración de scripts, para saber qué script va antes que otro.

– Gestionar los índices de los scripts de base de datos en el control de versiones se vuelve un pelín más complicado, sobre todo al utilizar ramas.Para evitar esto, debemos actualizar frecuentemente nuestras copias locales del proyecto, para darnos cuenta de posibles nuevos scripts de nuestros compañeros que nos hagan cambiar la numeración de los scripts que vamos a subir.

– Como los cambios que hacen los desarrolladores están en ficheros separados, con distinto nombre, aunque dos personas toquen el mismo punto de la base de datos en sus scripts, el control de versiones no lanzará un conflicto.Necesitaremos otras herramientas, o más comunicación entre nosotros para darnos cuenta los conflictos que pongan en peligro la compatibilidad de scripts.

Algunos ejemplos de herramientas que siguen este enfoque de incrementales son Flyway, DBMantain, DbDeploy.

Versionar el esquema de base de datos en un único fichero (o versionar el estado de la base de datos).

En este enfoque iremos evolucionado y versionando un único fichero con el esquema de base de datos.
Iremos dejando en el control de versiones el estado final de la base de datos en cada versión, sin subir las pequeñas modificaciones hasta llegar a ese estado.
Por ejemplo, cada vez que modifiquemos una tabla de nuestra base de datos, subiremos el último script de creación de dicha tabla al control de versiones.
Si necesitamos añadir una nueva columna a una tabla de la línea base, no subiremos un script de modificación de la tabla añadiendo dicha columna.
En su lugar subiremos un nuevo script de creación de la tabla donde quede incluida esa nueva columna.

Ventajas:

– Es sencillo crear nuevos entornos desde cero, ya que solo tendremos que bajarnos la última versión del fichero de base de datos y ejecutarlo.

– Es más sencillo ver las diferencias de versiones en el control de versiones y saber qué ha cambiado de una versión a otra.

– Y de la misma manera, podemos gestionar los cambios de base de datos como los cambios en el código: nuestro control de versiones nos indicará dentro del mismo fichero quién ha añadido una línea de código, quién la ha borrado y cuándo.

– También es más sencillo gestionar ramas, merges y conflictos. Aparecerán conflictos al hacer cambios sobre las mismas partes del esquema y seremos conscientes de dichos conflictos. Por ello podremos resolverlos antes de ejecutar los scripts en nuestra base de datos.

Desventajas:

Como solo tenemos el estado final de la base de datos después de los cambios, solo tenemos scripts de creación, cada vez que queramos desplegar una versión de código y base de datos, tendremos que borrar la base de datos antigua y ejecutar los nuevos scripts.
Es decir, con cada despliegue borraremos y crearemos la base de datos de cero.
Esto para entornos bajos, como desarrollo y pruebas puede ser una opción, pero para entornos de producción no suele utilizarse.
Por ello mucha gente utiliza el enfoque de versionar el estado de la base de datos durante desarrollo y pruebas, y utiliza versionado por incrementales al pasar a entornos altos.
Herramientas como las que nos ofrece Redgate (SQL Source Control, SQL Compare) pueden ayudarnos a usar este enfoque.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Share This
Ir arriba