Quali sono i modi efficienti per gestire gli schemi di database condivisi tra i rami del codice?


12

Lavorare su un progetto con più rami, in cui ogni ramo viene infine unito al ramo principale, e in sostanza viene isolato per sviluppare una nuova funzionalità.

Il database, che è MS SQL Server, ha uno schema condiviso, tuttavia ogni ramo apporta modifiche allo schema man mano che procede.

La mia indagine principale è quali sono i modi migliori per gestire la condivisione dello schema dal ramo principale fino al ramo derivato, in modo tale che le modifiche apportate al ramo principale vengano facilmente unite nel ramo derivato, senza intervenire su nuove modifiche nel derivato ramo?


2
Solo l'unione deve essere gestita come qualsiasi altro codice: unione automatica, con fallback di intervento dell'utente e ispezione / verifica del risultato. (Preferisco il modo in cui il VS Database Project gestisce gli schemi con un oggetto per file.). La cosa delicata viene da come funzionano le migrazioni in avanti dei database esistenti ;-)

2
Ciò dipende fortemente dal modo in cui si sta verificando lo schema. Stai memorizzando gli script di creazione per gli oggetti di base più gli script di modifica? Stai utilizzando uno strumento di confronto degli schemi per generare script alter per migrare tra le versioni? Progetti di database VS2010?
Mark Storey-Smith,


Risposte:


7

Ho usato con successo la seguente metodologia, elaborata nel controllo versione e nel tuo database :

  • mantenere un numero di versione nei metadati (utilizzo una proprietà estesa del database)
  • qualsiasi modifica dello schema è codificata come uno script che aggiorna dalla versione corrente alla versione successiva
  • l'applicazione viene fornita con tutti gli script per l'aggiornamento dalla versione 0 (distribuzione iniziale) fino alla versione corrente
  • Ogni modifica viene effettuata tramite uno script. Comprese le modifiche ai dati "di sistema" come dizionari e voci della tabella di ricerca.
  • una volta distribuita, l'applicazione verifica la versione dello schema su disco, quindi esegue tutti i passaggi di aggiornamento per portare lo schema alla versione corrente richiesta

Sento spesso l'opinione di "in che modo è diverso dal mantenere gli script di definizione dell'oggetto sotto il controllo del codice sorgente?". La differenza è enorme, perché quando distribuisci una nuova versione dell'app non creerai semplicemente un nuovo database. La maggior parte delle volte la tua app dovrà aggiornare il database esistente, inclusi i dati esistenti . Questa è una differenza cruciale, i passaggi dell'aggiornamento devono garantire l'integrità e la coerenza dei dati esistenti durante l'aggiornamento. Alcune operazioni sono banali nel codice (aggiungi una colonna non nullable con valore predefinito allo script di definizione dell'oggetto tabella, fatto), ma in realtà sono estremamente dolorose durante la distribuzione effettiva (la tabella ha 1,5 miliardi di righe, la colonna add si esaurirebbe dello spazio di registro se eseguito in modo "semplice").

Come funziona con le ramificazioni:

  • quando viene creato il ramo, scatta la versione corrente dello schema, diciamo la versione 1.6
  • quando il team inizia a lavorare sul ramo, aggiunge una nuova versione, 1.7, e quindi inizia a codificare il passaggio di aggiornamento da 1.6 a 1.7
  • il passaggio di aggiornamento viene modificato man mano che vengono apportate modifiche nel ramo. Esegue sempre lo script che si aggiorna dalla v 1.6 alla 1.7, ma ciò che fanno esattamente quegli script è soggetto alle normali iterazioni di codice e check-in nel ramo
  • il ramo termina lo sviluppo, si prepara per l'integrazione inversa (da ricollegare alla base)
    • esegue una nuova integrazione diretta dalla linea di base alla diramazione. Se l'integrazione non porta alcuna modifica alla versione dello schema, tutto è a posto, il ramo può invertire l'integrazione così com'è. la versione 1.7 diventa la nuova versione di base.
    • la cosa interessante è quando nel frattempo un altro ramo si è integrato al contrario nella base e ora la versione dello schema di base è cambiata, diciamo, 1.7. In questo caso la nostra filiale deve portare la versione dello schema di destinazione della distribuzione su 1.8 ed effettuare una revisione del passaggio di aggiornamento che era precedentemente dalla 1.6 alla 1.7 per vedere come funziona nel nuovo ambiente, aggiornando dalla 1.7 alla 1.8. I conflitti di schema logico devono essere risolti, lo script può richiedere modifiche, il test deve essere eseguito. Una volta completato, il ramo può invertire l'integrazione nella base. La versione di destinazione distribuita del prodotto ora diventa 1.8.
    • quando un altro ramo che ha biforcato alla versione 1.6 dello schema vuole integrarsi al contrario, deve eseguire il bump della sua versione dello schema alla 1.9, testare lo script di aggiornamento dalla 1.8 alla 1.9, quindi può integrarsi nuovamente nella base.

Si noti che non sono coinvolti strumenti, script di diff diffici di schemi magici, procedure guidate e script generati da clic con il tasto destro. Questo è un processo guidato dallo sviluppatore al 100%, basato sull'origine (script). Molti ritengono che questo intero processo sia elaborato, ma funziona. In effetti, come utente di SQL Server, hai già sfruttato i risultati di questo processo nell'uso quotidiano di SQL Server: SQL Server stesso utilizza un processo di aggiornamento del database molto simile e, come probabilmente ti aspetti, il processo di sviluppo del prodotto fa ampio uso di ramificazione e il problema che hai citato è un problema molto reale che deve essere risolto.

A proposito, il modo in cui la ramificazione / integrazione si verifica in realtà differisce tra i prodotti di controllo del codice sorgente, sto usando i termini familiari dalla modalità operativa di integrazione integrale .


+1, in particolare per ogni modifica effettuata tramite uno script
a_horse_with_no_name

1

Mentre la mia risposta potrebbe non essere lunga come quella di Remus, ho trovato che questa era davvero una buona soluzione. Non l'ho ancora installato in produzione, quindi YMMV *.

Liquibase

Essenzialmente è un file XML in cui si apportano modifiche allo schema del database come nuovi elementi all'interno del file XML. Per esempio:

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

Ha una sintassi completamente definita, quindi puoi praticamente fare tutto ciò che vuoi sul tuo database.

Nell'installazione Liquibase è inoltre possibile specificare quale database si desidera eseguire il controllo delle versioni. Quindi "esegui" il file .xml con l'eseguibile Java incluso (file jar). Questo essenzialmente ricrea le modifiche specificate nell'XML nel database.

Il vero kicker è che memorizzi questo file XML nella stessa cartella con versione del tuo codice. Quindi nel mio caso era Git. Avevo questo file XML nella mia cartella del progetto (lo stesso livello di /.git) e ogni volta che passavo da un ramo all'altro il file XML cambiava in quella versione di ramo e correvo il file .jar e il mio database ora rifletteva quel ramo.

* Nota: non ho completato l'implementazione perché ho avuto problemi a connettere Java a SQL Server. Ha bisogno di alcuni driver jdbc e simili e non ero dell'umore giusto. Quindi, il tuo chilometraggio può variare.


1

Qui a Red Gate rilasceremo presto una soluzione di controllo delle versioni del database che sfrutta sia SQL Compare che SQL Source Control. Questo utilizza un approccio di aggiornamento degli script di migrazione e contrassegna il database con una proprietà estesa della versione che corrisponde a una revisione del controllo del codice sorgente.

Speriamo di rilasciare a metà dicembre. È ora disponibile un candidato al rilascio. Per maggiori informazioni visita:

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

Speriamo di sviluppare questa soluzione nei prossimi mesi, quindi fateci sapere cosa ne pensate.


0

Se tu e gestisci le modifiche allo schema generando script e mantenendo tali script sotto il controllo del codice sorgente, dovresti essere in grado di trattare le modifiche come faresti per unire qualsiasi altro codice. Puoi scegliere di unire automaticamente o fare più interventi manuali.


Non proprio no. L'unione manuale di oggetti di creazione di script di script è fattibile ma altera, gli inserimenti di dati di riferimento e gli script di movimento di dati diventano molto disordinati, molto rapidamente.
Mark Storey-Smith,

Concordato. Qui a Red Gate crediamo che gli script di creazione si fonderanno abbastanza bene e potrebbero essere automatizzati. Tuttavia, gli script di migrazione tra le versioni dovranno essere uniti a mano per evitare ordini di dipendenza errati e duplicazione del codice di modifica.
David Atkinson,

0

Mi trovo in una situazione simile in cui lavoro su un sito Web dal vivo e in diversi rami di sviluppo in cui è necessario modificare lo schema del database.

L'ho risolto scrivendo un post-checkout e un hook post-merge che possono essere usati bene con git. Conservo tutte le mie migrazioni sotto forma di file SQL in una directory separata e le commetto insieme al codice PHP modificato. Ogni volta che eseguo un

git checkout

o a

git merge

git chiamerà automaticamente le migrazioni up e down appropriate. Vedi la mia implementazione su Github .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.