Volver a ejecutar secuencias de commands de desarrollo de bases de datos

En nuestro entorno actual de desarrollo de database, hemos automatizado los processs de compilation para verificar todo el código sql de svn create scripts de database y aplicarlos a las diversas bases de datos de desarrollo / qa.

Todo está muy bien, y es una tremenda mejora con respecto a lo que hicimos en el pasado, pero tenemos un problema con volver a ejecutar las secuencias de commands. Obviamente, este no es un problema con algunos scripts como la alteración de procedimientos, ya que puede ejecutarlos una y otra vez sin afectar adversamente el sistema. Ahora mismo para agregar metadatos y ejecutar sentencias como crear / modificar declaraciones de tabla, agregamos código para verificar y ver si los objects existen, y si lo hacen, no los ejecuten.

Nuestro problema es que realmente solo tenemos una oportunidad para ejecutar el script, porque una vez que el script se ha ejecutado, los objects están en el entorno y el sistema no volverá a ejecutar el script. Si algo necesita cambiar una vez que se ha implementado, tenemos un process difícil de ejecutar scripts de actualización contra los scripts de actualización y esperando que todo caiga en el order correcto y que todos los PK se alineen entre los entornos (las bases de datos son, digamos , "especial").

Aparte de abandonar la database y comenzar el process desde cero (la última versión más reciente), ¿alguien tiene una solución más elegante para esto?

No estoy seguro de cuál es la mejor manera de abordar el problema en su entorno específico, pero le sugiero que lea la function de migraciones de Rail para get información sobre cómo comenzar.

http://wiki.rubyonrails.org/rails/pages/UnderstandingMigrations

Nos ocupamos de esto – o al less un problema similar a este – de la siguiente manera:

  1. El esquema tiene un número de versión: esto se representa mediante una tabla que tiene una fila por versión que, además del número de versión, lleva elementos aburridos como una marca de date / hora para cuando esa versión entró en existencia.
  2. Al hacer que el esquema cree / modifique DDL envuelto en código que realiza los cambios para nosotros.

En el context anterior, uno buildía el código de cambio de esquema como parte del process de compilation, luego lo ejecutaría y solo aplicaría los cambios de esquema que no se hayan aplicado.

Según nuestra experiencia (que no es necesariamente representativo) en la mayoría de los casos, los cambios de esquema son suficientemente pequeños / rápidos para poder ejecutarlos de manera segura en una transacción, lo que significa que si falla, obtenemos una reversión y el db es "seguro" – aunque uno siempre recomendaría tomar copys de security antes de aplicar actualizaciones de esquema si es posible.

Lo desarrollé a partir de una desagradable experiencia dolorosa. No es un sistema perfecto (o una idea original) pero como resultado de trabajar de esta manera tenemos un alto grado de confianza de que si hay dos instancias de una de nuestras bases de datos con la misma versión que el esquema de esas dos bases de datos ser el mismo en casi todos los aspectos y que podemos llevar cualquier file db al esquema actual para esa aplicación sin efectos nocivos. (Eso último no es 100% cierto, lamentablemente, siempre hay una exception, ¡pero no está muy lejos de la verdad!)

¿Mantiene sus datos existentes en la database? Si no, es posible que desee ver algo similar a lo que Matt mencionó para .NET llamado RikMigrations

http://www.rikware.com/RikMigrations.html 

Utilizo eso en mis proyectos para actualizar mi database sobre la marcha, mientras sigo las revisiones. Además, hace que sea muy sencillo mover el esquema de la database a diferentes serveres, etc.

si desea tener capacidad de repetición en sus scripts, entonces no puede tenerlos como definiciones … lo que quiero decir con esto es que debe centrarse en los scripts de cambio en lugar de aquí es mi script de tabla.

digamos que tiene una table Clientes:

 create table Customers ( id int identity(1,1) primary key, first_name varchar(255) not null, last_name varchar(255) not null ) 

y luego quieres agregar una columna de estado. No modifique su script de tabla original, ya se haya ejecutado (y pueda tener la syntax if (! Exists) para evitar que cause errores mientras se ejecuta de nuevo).

En su lugar, tenga una nueva secuencia de commands, llamada add_customer_status.sql

en este script tendrás algo como:

 alter table Customers add column status varchar(50) null update Customers set status = 'Silver' where status is null alter table Customers alter column status varchar(50) not null 

Nuevamente puede envolver esto con un bloque if (! Exists) para permitir la repetición de la ejecución, pero aquí aprovechamos la noción de que este es un script de cambio, y adaptamos la database en consecuencia. Si ya hay datos en la tabla de clientes, seguimos estando bien, ya que agregamos la columna, la iniciamos con datos y luego agregamos la restricción no nula.

Ambos frameworks de migration mencionados anteriormente son buenos, también he tenido una excelente experiencia con MigratorDotNet .

Scott nombró algunas otras herramientas SQL que abordan el problema de la gestión del cambio. Pero todavía estoy haciendo lo mío.

Me gustaría secundar esta pregunta, y agregar mi perplejidad de que aún no existe una herramienta gratuita y basada en la comunidad para este problema. Obviamente, los scripts no son una forma satisfactoria de mantener un esquema de database; tampoco son instancias. Entonces, ¿por qué no guardamos los metadatos en un formatting separado (y mientras estamos en eso, plataforma neutral)?

Eso es lo que estoy haciendo ahora. Mi esquema maestro de database es un file XML controlado por la versión, creado inicialmente a partir de un service web simple. Un simple progtwig de javascript compara instancias contra él, y una simple transformación XSL produce las sentencias CREATE o ALTER. Tiene límites, como RikMigrations ; por ejemplo, no siempre secuencia correctamente los objects interdependientes. (Pero adivinen qué, tampoco lo hace la herramienta de publicación de bases de datos SQL Server de Microsoft .) De verdad, es demasiado simple. Simplemente no incluí objects (roles, usuarios, etc.) que no estaba usando.

Por lo tanto, mi punto de vista es que este problema no se aborda adecuadamente, y que tarde o temprano tendremos que unirnos y abordar los detalles diabólicos.

Fuimos a la ruta 'soltar y recrear el esquema'. Tuvimos algunas classs en nuestro package de testing JUnit que parametrizó los scripts para crear todos los objects en el esquema para el desarrollador que ejecuta el código. Esto permitió a todos los desarrolladores compartir una database de testing y todos podían crear / probar / soltar simultáneamente sus tablas de testing sin conflictos.

¿Tomó mucho time para correr? Sí. Al principio usamos el método de configuration para esto, lo que significaba que las tablas se descartaban / creaban para cada testing y eso llevó demasiado time. Luego creamos un TestSuite que se podía ejecutar una vez antes de todas las testings para una class y luego se limpiaba cuando se completaban todas las testings de la class. Esto todavía significaba que la configuration de db se ejecutó muchas veces cuando ejecutamos nuestra class 'AllTests', que incluía todas las testings en todos nuestros packages. La forma en que lo resolví fue agregar un semáforo al código OracleTestSuite, así que cuando la primera testing solicitó que se configurara la database, lo haría, pero cualquier llamada subsiguiente simplemente incrementaría un contador. Como se llamaba a cada método tearDown (), el contador disminuía el contador hasta que llegaba a 0 y el código OracleTestSuite soltaba todo. Un problema que esto deja es si las testings asumen que la database está vacía. Puede ser conveniente dejar que las testings de la database conozcan el order en que se ejecutan para que puedan aprovechar el estado de la database, ya que puede networkingucir la duplicación de la configuration de la database.

Usamos el concepto de ObjectMothers para resolver un problema similar con la creación de objects de dominio complejos con fines de testing. Los objects simulados podrían ser una mejor respuesta, pero no habíamos oído hablar de ellos en ese momento. Después de todo este time, recomendaría crear methods de testing de ayuda que podrían crear sets de datos estandarizados para los escenarios típicos. Además, eso ayudaría a documentar los casos más importantes desde una perspectiva de datos.