¿Cuáles son las formas eficientes de manejar los esquemas de bases de datos que se comparten entre las ramas de código?

12

Trabajando en un proyecto con varias ramas, donde cada rama se fusiona con la rama principal y, en esencia, se aísla para desarrollar una nueva característica.

La base de datos, que es MS SQL Server, tiene un esquema compartido, sin embargo, cada rama realiza cambios en el esquema a medida que avanza.

Mi consulta principal es cuáles son buenas maneras de tratar de compartir el esquema desde la rama principal hasta la rama derivada, de modo que los cambios que se realizan en la rama principal se fusionen fácilmente en la rama derivada, sin pisar nuevos cambios en la derivada ¿rama?


fuente
2
Solo la fusión debe manejarse como cualquier otro código: fusión automática, con respaldo de intervención del usuario e inspección / prueba del resultado. (Prefiero la forma en que VS Database Project maneja esquemas con un objeto por archivo). Lo complicado viene con cómo funcionan las migraciones hacia adelante de las bases de datos existentes ;-)
2
Esto depende en gran medida de cómo está versionando el esquema. ¿Está almacenando guiones de creación para los objetos base más guiones de alteración? ¿Está utilizando una herramienta de comparación de esquemas para generar scripts alternos para migrar entre versiones? Proyectos de bases de datos VS2010?
Mark Storey-Smith
Discusión relevante: dba.stackexchange.com/questions/2/…
Nick Chammas
1
También relevante: martinfowler.com/articles/…
Nick Chammas

Respuestas:

7

He utilizado con éxito la siguiente metodología, elaborada en el Control de versiones y su Base de datos :

  • mantener un número de versión en metadatos (uso una propiedad extendida de base de datos)
  • cualquier cambio de esquema se codifica como un script que se actualiza desde la versión actual a la siguiente versión
  • la aplicación se envía con todos los scripts para actualizar desde la versión 0 (implementación inicial) hasta la versión actual
  • Cada cambio se realiza a través de un script. Incluyendo cambios en los datos del 'sistema' como diccionarios y entradas en la tabla de búsqueda.
  • cuando se implementa, la aplicación verifica la versión del esquema en el disco, luego ejecuta todos los pasos de actualización para llevar el esquema a la versión actual requerida

A menudo escucho la opinión de '¿en qué se diferencia esto de solo mantener los scripts de definición de objetos bajo control de origen?'. La diferencia es enorme, porque cuando implementa una nueva versión de su aplicación, no va a crear simplemente una nueva base de datos. La mayoría de las veces su aplicación tendrá que actualizar la base de datos existente, incluidos los datos existentes . Esta es una diferencia crucial, sus pasos de actualización deben garantizar la integridad y la coherencia de los datos existentes durante la actualización. Algunas operaciones son triviales en el código (agregue una columna no anulable con valor predeterminado al script de definición de objeto de tabla, hecho), pero de hecho son muy dolorosas en el despliegue real (la tabla tiene 1.5 mil millones de filas, la columna de agregar se agotaría de espacio de registro si se hace de la manera 'simpleton').

¿Cómo funciona esto con la ramificación?

  • cuando se crea la rama, se ajusta la versión actual del esquema, digamos la versión 1.6
  • A medida que el equipo comienza a trabajar en la sucursal, agrega una nueva versión, 1.7, y luego comienza a codificar el paso de actualización de 1.6 a 1.7
  • el paso de actualización cambia a medida que se realizan modificaciones en la rama. Siempre ejecuta la secuencia de comandos que actualiza de v 1.6 a 1.7, pero lo que hacen exactamente esas secuencias de comandos está sujeto a las iteraciones de código normales y los registros en la rama
  • la rama finaliza el desarrollo, se prepara para la integración inversa (para fusionarse nuevamente en la línea de base)
    • realiza una nueva integración hacia adelante desde la línea base hasta la rama. Si la integración no trae ningún cambio en la versión del esquema, todo está bien, la rama puede revertir la integración tal como está. La versión 1.7 se convierte en la nueva versión de referencia.
    • Lo interesante es cuando otra rama se ha integrado inversamente en la base mientras tanto y ahora la versión del esquema base ha cambiado a, digamos, 1.7. En este caso, nuestra sucursal tiene que aumentar su versión de esquema de destino de implementación a 1.8 y hacer una revisión del paso de actualización que anteriormente era de 1.6 a 1.7 para ver cómo funciona en el nuevo entorno, actualizando de 1.7 a 1.8. Los conflictos de esquema lógico tienen que resolverse, el script puede requerir cambios, las pruebas deben hacerse. Una vez completado, la rama puede revertir la integración en la base. La versión de destino implementada del producto ahora se convierte en 1.8.
    • cuando otra bifurcación que se bifurca en la versión de esquema 1.6 quiere integrarse inversamente, tendrá que cambiar su versión de esquema a 1.9, probar el script de actualización de 1.8 a 1.9, luego puede integrarse nuevamente en la base.

Tenga en cuenta que no hay ninguna herramienta involucrada, no hay secuencias de comandos de diferencias de esquema mágico, no hay asistentes y no hay una secuencia de comandos de clic con el botón derecho involucrada. Este es un proceso 100% dirigido por el desarrollador, basado en la fuente (scripts). Muchos encuentran todo este proceso elaborado, pero funciona. De hecho, como usuario de SQL Server, ya ha aprovechado los resultados de este proceso en su uso diario de SQL Server: SQL Server utiliza un proceso de actualización de base de datos muy similar y, como probablemente espera, el proceso de desarrollo de productos hace un uso extensivo de ramificación y el problema que mencionó es un problema muy real que debe resolverse.

Por cierto, cómo ocurre realmente la ramificación / integración difiere entre los productos de control de origen, estoy usando los términos familiares del modo de operación forzosamente integrado .

Remus Rusanu
fuente
+1, especialmente para Cada cambio se realiza a través de un script
a_horse_with_no_name
1

Si bien mi respuesta podría no ser tan larga como la de Remus, encontré que esta es una muy buena solución. Todavía no lo tengo configurado en producción, así que YMMV *.

Liquibase

Esencialmente es un archivo XML donde realiza cambios de esquema en su base de datos como nuevos elementos dentro del archivo XML. Por ejemplo:

<createTable tableName="department">
            <column name="id" type="int">
                <constraints primaryKey="true" nullable="false"/>
            </column>

Tiene una sintaxis completamente desarrollada para que pueda hacer casi todo lo que quiera en su base de datos.

También especifica en su instalación de Liquibase qué base de datos desea versionar. Luego, "ejecuta" el .xml con el ejecutable Java incluido (archivo jar). Esto esencialmente recrea esos cambios especificados en el XML en su base de datos.

El verdadero truco es que almacena este archivo XML en la misma carpeta versionada que su código. Entonces, en mi caso, ese fue Git. Tenía este archivo XML en la carpeta de mi proyecto (mismo nivel que /.git) y luego, cada vez que cambiaba de rama, el archivo XML cambiaba a esa versión de rama y ejecutaba el archivo .jar y mi base de datos ahora reflejaba esa rama.

* Nota: No he terminado la implementación porque tuve problemas para conectar Java a SQL Server. Necesita algunos controladores jdbc y tal, y no estaba de humor. Por lo tanto, su kilometraje puede variar.

MikeMurko
fuente
1

Aquí en Red Gate pronto lanzaremos una solución de versiones de base de datos que aprovecha SQL Compare y SQL Source Control. Esto utiliza un enfoque de actualización de scripts de migración y sella la base de datos con una propiedad extendida de versión que corresponde a una revisión de control de origen.

Esperamos lanzar a mediados de diciembre. Hay un candidato de lanzamiento disponible ahora. Para más información visite:

http://www.red-gate.com/products/sql-development/sql-source-control/entrypage/migration

Esperamos aprovechar esta solución en los próximos meses, así que háganos saber lo que piensa.

David Atkinson
fuente
0

Si usted y el manejo de sus cambios de esquema al generar scripts y mantener esos scripts bajo control de origen, entonces debería poder tratar los cambios como lo haría con cualquier otra combinación de código. Puede elegir fusionar automáticamente o realizar más intervención manual.


fuente
No, realmente no. La fusión manual de los scripts de creación de objetos base es viable, pero la modificación, las inserciones de datos de referencia y los scripts de movimiento de datos se vuelven muy desordenados, muy rápidamente.
Mark Storey-Smith
Convenido. Aquí en Red Gate creemos que los scripts de creación se fusionarán bastante bien y podrían automatizarse. Sin embargo, las secuencias de comandos de migración entre versiones deberán fusionarse a mano para evitar un orden de dependencia incorrecto y la duplicación del código de cambio.
David Atkinson
0

Estoy en una situación similar en la que trabajo en un sitio web en vivo y varias ramas de desarrollo en las que necesito cambiar el esquema de la base de datos.

Lo resolví escribiendo un post-checkout y un gancho posterior a la fusión que se puede usar muy bien con git. Almaceno todas mis migraciones en forma de archivos SQL en un directorio separado y las confirmo junto con el código PHP modificado. Cada vez que realizo un

git checkout

o un

git merge

git llamará automáticamente a las migraciones ascendentes y descendentes apropiadas. Vea mi implementación en Github .

Richard Brinkman
fuente