Come dovresti build il tuo database dal controllo del codice sorgente?

Ci sono state alcune discussioni sulla wiki della comunità SO sul fatto che gli oggetti del database dovrebbero essere controllati dalla versione. Tuttavia, non ho visto molte discussioni sulle migliori pratiche per la creazione di un processo di automazione build per gli oggetti del database.

Questo è stato un punto di discussione polemico per il mio team, in particolare dal momento che gli sviluppatori e i DBA hanno spesso obiettivi, approcci e preoccupazioni diversi nella valutazione dei vantaggi e dei rischi di un approccio di automazione all’implementazione del database.

Mi piacerebbe sentire alcune idee dalla comunità SO su quali pratiche sono state efficaci nel mondo reale.

Mi rendo conto che è in qualche modo soggettivo quali sono le pratiche migliori, ma penso che un buon dialogo su quale lavoro possa essere utile a molte persone.

Ecco alcune delle mie domande sul teaser sulle aree di interesse in questo argomento. Questi non sono intesi per essere una lista definitiva – piuttosto un punto di partenza per le persone per aiutare a capire quello che sto cercando.

  1. Dovrebbero essere costruiti sia gli ambienti di test che quelli di produzione dal controllo del codice sorgente?
    • Dovrebbero essere entrambi costruiti usando l’automazione – o la produzione dovrebbe essere creata copiando oggetti da un ambiente di test stabile e finalizzato?
    • Come gestite le potenziali differenze tra gli ambienti di test e di produzione negli script di distribuzione?
    • Come si verifica che gli script di implementazione funzionino in modo altrettanto efficace rispetto alla produzione come avviene nel test?
  2. Quali tipi di oggetti dovrebbero essere controllati dalla versione?
    • Solo codice (procedure, pacchetti, trigger, java, ecc.)?
    • Indici?
    • Vincoli?
    • Definizioni di tabella?
    • Script di modifica tabella? (ad es. script ALTER)
    • Qualunque cosa?
  3. Quali tipi di oggetti non dovrebbero essere controllati dalla versione?
    • Sequenze?
    • Borse di studio?
    • Profili utente?
  4. Come devono essere organizzati gli oggetti del database nel repository SCM?
    • Come gestisci cose una tantum come gli script di conversione o gli script ALTER?
    • Come gestisci gli oggetti ritirati dal database?
    • Chi dovrebbe essere responsabile della promozione degli oggetti dallo sviluppo al livello di test?
    • Come coordinate i cambiamenti da più sviluppatori?
    • Come gestisci la ramificazione per gli oggetti di database utilizzati da più sistemi?
  5. Quali eccezioni, se ce ne sono, possono essere ragionevoli apportate a questo processo?
    • Problemi di sicurezza?
    • Dati con problemi di de-identificazione?
    • Script che non possono essere completamente automatizzati?
  6. Come si può rendere il processo elastico e applicabile?
    • Per errore dello sviluppatore?
    • A problemi ambientali imprevisti?
    • Per il ripristino di emergenza?
  7. Come convincete i responsabili delle decisioni che i vantaggi di DB-SCM giustificano veramente il costo?
    • Prove aneddotiche?
    • Ricerca industriale?
    • Raccomandazioni sulle migliori pratiche del settore?
    • Ricorsi alle autorità riconosciute?
    • Analisi costi benefici?
  8. Chi dovrebbe “possedere” oggetti di database in questo modello?
    • Gli sviluppatori?
    • DBA?
    • Analisti di dati?
    • Più di una?

Ecco alcune risposte alle tue domande:

  1. Dovrebbero essere costruiti sia gli ambienti di test che quelli di produzione dal controllo del codice sorgente?
    • Dovrebbero essere entrambi costruiti usando l’automazione – o la produzione dovrebbe essere creata copiando oggetti da un ambiente di test stabile e finalizzato?
    • Automazione per entrambi. NON copiare dati tra gli ambienti
    • Come gestite le potenziali differenze tra gli ambienti di test e di produzione negli script di distribuzione?
    • Utilizzare i modelli, in modo che in realtà si generi diversi set di script per ogni ambiente (ad esempio riferimenti a sistemi esterni, database collegati, ecc.)
    • Come si verifica che gli script di implementazione funzionino in modo altrettanto efficace rispetto alla produzione come avviene nel test?
    • Verificali sull’ambiente di pre-produzione: verifica la distribuzione sulla copia esatta dell’ambiente di produzione (database e potenzialmente altri sistemi)
  2. Quali tipi di oggetti dovrebbero essere controllati dalla versione?
    • Solo codice (procedure, pacchetti, trigger, java, ecc.)?
    • Indici?
    • Vincoli?
    • Definizioni di tabella?
    • Script di modifica tabella? (ad es. script ALTER)
    • Qualunque cosa?
    • Tutto e:
      • Non dimenticare i dati statici (elenchi di ricerca, ecc.), Quindi non è necessario copiare TUTTI i dati tra ambienti
      • Conserva solo la versione corrente degli script del database (versione controllata, ovviamente) e
      • Memorizza gli script ALTER: 1 script BIG (o una directory di script con nome 001_AlterXXX.sql, in modo che eseguendoli in ordine naturale si aggiorni dalla versione A alla B)
  3. Quali tipi di oggetti non dovrebbero essere controllati dalla versione?
    • Sequenze?
    • Borse di studio?
    • Profili utente?
    • vedere 2. Se i tuoi utenti / ruoli (o nomi utente tecnici) sono diversi tra gli ambienti, puoi comunque copiarli usando i modelli (vedi 1.)
  4. Come devono essere organizzati gli oggetti del database nel repository SCM?
    • Come gestisci cose una tantum come gli script di conversione o gli script ALTER?
    • vedere 2.
    • Come gestisci gli oggetti ritirati dal database?
    • cancellato dal DB, rimosso dal trunk / tip di controllo sorgente
    • Chi dovrebbe essere responsabile della promozione degli oggetti dallo sviluppo al livello di test?
    • programma dev / test / release
    • Come coordinate i cambiamenti da più sviluppatori?
    • prova a NON creare un database separato per ogni sviluppatore. usi il controllo del codice sorgente, giusto? in questo caso gli sviluppatori cambiano il database e archiviano gli script. per essere completamente sicuro, ricreare il database dagli script durante la compilazione notturna
    • Come gestisci la ramificazione per gli oggetti di database utilizzati da più sistemi?
    • dura: cerca di evitare a tutti i costi.
  5. Quali eccezioni, se ce ne sono, possono essere ragionevoli apportate a questo processo?
    • Problemi di sicurezza?
    • non memorizzare password per test / prod. puoi permetterlo per dev, specialmente se hai automatizzato le ricostruzioni DB giornaliere / notturne
    • Dati con problemi di de-identificazione?
    • Script che non possono essere completamente automatizzati?
    • documenta e memorizza con le informazioni di rilascio / script ALTER
  6. Come si può rendere il processo elastico e applicabile?
    • Per errore dello sviluppatore?
    • testato con build giornaliero da zero e confronta i risultati con l’aggiornamento incrementale (dalla versione A alla B usando ALTER). confrontare sia lo schema risultante che i dati statici
    • A problemi ambientali imprevisti?
    • utilizzare il controllo della versione e i backup
    • confrontare lo schema del database PROD con ciò che si pensa, specialmente prima della distribuzione. DBA SuperDuperCool potrebbe aver corretto un errore che non era mai stato nel tuo sistema di ticket 🙂
    • Per il ripristino di emergenza?
  7. Come convincete i responsabili delle decisioni che i vantaggi di DB-SCM giustificano veramente il costo?
    • Prove aneddotiche?
    • Ricerca industriale?
    • Raccomandazioni sulle migliori pratiche del settore?
    • Ricorsi alle autorità riconosciute?
    • Analisi costi benefici?
    • se gli sviluppatori e gli amministratori di database sono d’accordo, non è necessario convincere nessuno, penso (a meno che non si abbia bisogno di soldi per acquistare un software come un dbGhost per MSSQL)
  8. Chi dovrebbe “possedere” oggetti di database in questo modello?
    • Gli sviluppatori?
    • DBA?
    • Analisti di dati?
    • Più di una?
    • Di solito i DBA approvano il modello (prima del check-in o dopo come parte della revisione del codice). Sono sicuramente gli oggetti relativi alle prestazioni. Ma in generale la squadra lo possiede [e datore di lavoro, ovviamente :)]

Trovo lo SQL come codice sorgente quando ansible

Se riesco a scriverlo nello standard SQL conforms allo standard, in genere viene inserito in un file nel mio controllo sorgente. Il file definirà il più ansible, come le dichiarazioni SP, Table CREATE.

Includo anche i dati fittizi per i test nel controllo del codice sorgente:

  1. proj / sql / setup_db.sql
  2. proj / sql / dummy_data.sql
  3. proj / sql / mssql_specific.sql
  4. proj / sql / mysql_specific.sql

E poi estrapro tutte le mie query SQL in modo che possa build l’intero progetto per MySQL, Oracle, MSSQL o qualsiasi altra cosa.

L’automazione di build e test utilizza questi script di build in quanto sono importanti quanto l’origine dell’app e verifica tutto dall’integrità tramite trigger, procedure e registrazione.

Utilizziamo l’integrazione continua tramite TeamCity. Ad ogni controllo al controllo del codice sorgente, il database e tutti i dati del test vengono ricostruiti da zero, quindi il codice, quindi i test delle unità vengono eseguiti sul codice. Se stai usando uno strumento di generazione del codice come CodeSmith, può anche essere inserito nel tuo processo di generazione per generare il tuo livello di accesso ai dati fresco con ogni build, assicurandoti che tutti i livelli “si abbinino” e non producano errori dovuti a parametri SP non corrispondenti o colonne mancanti.

Ogni build ha una propria collezione di script SQL che sono memorizzati nella directory $ project \ SQL \ nel controllo del codice sorgente, assegnato un prefisso numerico ed eseguito nell’ordine. In questo modo, stiamo esercitando la nostra procedura di implementazione ad ogni build.

A seconda della tabella di ricerca, la maggior parte dei nostri valori di ricerca viene anche memorizzata negli script ed eseguita per assicurarsi che i dati di configurazione siano quelli che ci aspettiamo, ad esempio, “reason_codes” o “country_codes”. In questo modo possiamo modificare i dati di ricerca in dev, testarli e quindi “promuoverli” attraverso QA e produzione, invece di utilizzare uno strumento per modificare i valori di ricerca nella produzione, che può essere pericoloso per il tempo di attività.

Creiamo anche una serie di script di “rollback” che annullano le modifiche al nostro database, nel caso in cui una build in produzione diventi vaga. È ansible testare gli script di rollback eseguendoli, quindi rieseguire i test delle unità per la versione di build precedente alla propria, dopo l’esecuzione degli script di distribuzione.

Facendo domande “teaser” sembra che tu sia più interessato a una discussione rispetto all’opinione di qualcuno sulle risposte finali. La mailing list triggers (> 2500 membri) agileDatabases ha affrontato molte di queste domande ed è, nella mia esperienza, un forum sofisticato e civile per questo tipo di discussione.

Sono sostanzialmente d’accordo con ogni risposta data da van . Per saperne di più, la mia linea di base per la gestione dei database è la serie di K. Scott Allen (assolutamente da leggere, IMHO. E anche l’opinione di Jeff sembra).

  • Gli oggetti del database possono sempre essere ricostruiti da zero avviando un singolo file SQL (che può chiamare anche altri file SQL): Create.sql . Questo può includere l’inserimento di dati statici (elenchi …).
  • Gli script SQL sono parametrizzati in modo che nessuna informazione dipendente dall’ambiente e / o sensibile sia archiviata in file normali.
  • Utilizzo un file batch personalizzato per avviare Create.sql : Create.cmd . Il suo objective è principalmente quello di verificare i prerequisiti (strumenti, variabili d’ambiente …) e inviare parametri allo script SQL. Può anche caricare in blocco i dati statici dai file CSV per problemi di prestazioni.
  • In genere, le credenziali dell’utente di sistema vengono passate come parametro al file Create.cmd .

IMHO, il caricamento dinamico dei dati dovrebbe richiedere un altro passo, a seconda del tuo ambiente. Gli sviluppatori vorranno caricare il loro database con dati di test, spazzatura o nessun dato, mentre all’altro capo della produzione i responsabili della produzione vorranno caricare i dati di produzione. Prenderò in considerazione la possibilità di memorizzare i dati di test anche nel controllo del codice sorgente (per facilitare il test dell’unità, ad esempio).

Una volta che la prima versione del database è stata messa in produzione, non sarà necessario solo creare script (principalmente per gli sviluppatori), ma anche aggiornare gli script (basati sugli stessi principi):

  • Ci deve essere un modo per recuperare la versione dal database (io uso una stored procedure, ma una tabella farebbe altrettanto bene).
  • Prima di rilasciare una nuova versione, creo un file Upgrade.sql (che può chiamarne altri) che consente di aggiornare la versione N-1 alla versione N (N essendo la versione rilasciata). Conservo questo script in una cartella denominata N-1 .
  • Ho un file batch che esegue l’aggiornamento: Upgrade.cmd . Può recuperare la versione corrente (CV) del database tramite una semplice istruzione SELECT, avviare lo script Upgrade.sql memorizzato nella cartella CV e eseguire il ciclo finché non viene trovata alcuna cartella. In questo modo, è ansible eseguire automaticamente l’aggiornamento da, ad esempio, da N-3 a N.

I problemi con questo sono:

  • È difficile confrontare automaticamente gli schemi di database, in base ai fornitori di database. Questo può portare a script di aggiornamento incompleti.
  • Ogni modifica all’ambiente di produzione (solitamente DBA per la regolazione delle prestazioni) dovrebbe trovare la sua strada anche al controllo del codice sorgente. Per essere sicuri di ciò, di solito è ansible registrare ogni modifica al database tramite un trigger. Questo registro viene ripristinato dopo ogni aggiornamento.
  • Più idealmente, tuttavia, le modifiche avviate da DBA dovrebbero essere parte del processo di rilascio / aggiornamento, quando ansible.

Per quanto riguarda il tipo di oggetti di database che vuoi avere sotto il controllo del codice sorgente? Bene, direi il più ansible, ma non di più 😉 Se si desidera creare utenti con password, ottenere loro una password predefinita (login / login, pratico per scopi di test unitari), e rendere la password modificare un’operazione manuale . Questo succede molto con Oracle, dove gli schemi sono anche utenti …

+1 per Liquibase : LiquiBase è una libreria open source (LGPL), indipendente dal database per il monitoraggio, la gestione e l’applicazione delle modifiche al database. Si basa su una premessa semplice: tutte le modifiche al database (struttura e dati) sono archiviate in modo descrittivo basato su XML e controllate nel controllo del codice sorgente. Il punto positivo è che le modifiche di DML sono memorizzate semanticamente, non solo diff, in modo da poter monitorare lo scopo delle modifiche.

Potrebbe essere combinato con il controllo della versione GIT per una migliore interazione. Configurerò il nostro ambiente di sviluppo per provarlo.

Inoltre, è ansible utilizzare Maven, i sistemi di build Ant per creare codice di produzione dagli script.

Tha minus è che LiquiBase non si integra in IDE SQL diffusi e dovresti fare da solo le operazioni di base.

In aggiunta a questo, è ansible utilizzare DBUnit per il test DB: questo strumento consente di utilizzare script di generazione dati per testare l’ambiente di produzione con la pulizia successiva.

A PARER MIO:

  1. Memorizza DML nei file in modo da poterli modificare.
  2. Automatizza il processo di creazione dello schema dal controllo del codice sorgente.
  3. A scopo di test, lo sviluppatore potrebbe utilizzare DB locali creati dal controllo del codice sorgente tramite il sistema di compilazione + caricare i dati di test con gli script o gli script DBUnit (dal controllo del codice sorgente).
  4. LiquiBase consente di fornire una “sequenza di esecuzione” di script per rispettare le dipendenze.
  5. Ci dovrebbe essere un team DBA che controlli il brunch principale con TUTTE le modifiche prima dell’utilizzo della produzione. Voglio dire che controllano il trunk / ramo da altri DBA prima di impegnarsi nel trunk MASTER. In modo che il master sia sempre coerente e pronto per la produzione.

Abbiamo affrontato tutti i problemi menzionati con le modifiche al codice, la fusione, la riscrittura nel nostro database di produzione di fatturazione. Questo argomento è ottimo per scoprire tutte queste cose.

Abbiamo il nostro progetto Silverlight con database MSSQL nel controllo di versione Git. Il modo più semplice è assicurarsi di avere un database snellito (per quanto riguarda i contenuti) e fare un dump completo di fe Visual Studio. Quindi puoi eseguire “sqlcmd” dal tuo script di build per ricreare il database su ogni macchina di sviluppo.

Per la distribuzione questo non è ansible poiché i database sono troppo grandi: questo è il motivo principale per averli in un database in primo luogo.

Sono fermamente convinto che un DB dovrebbe essere parte del controllo del codice sorgente e in larga parte parte del processo di compilazione. Se si trova nel controllo del codice sorgente, ho le stesse protezioni per la sicurezza del codice quando scrivo una procedura memorizzata in SQL come faccio quando scrivo una class in C #. Lo faccio includendo una directory di script DB sotto il mio albero dei sorgenti. Questa directory di script non ha necessariamente un file per un object nel database. Quello sarebbe un dolore nel sedere! Sviluppo nel mio db proprio come farei nel mio progetto di codice. Poi, quando sono pronto per il check-in, faccio una diff tra l’ultima versione del mio database e quella attuale su cui sto lavorando. Uso SQL Compare per questo e genera uno script di tutte le modifiche. Questo script viene quindi salvato nella mia directory db_update con una convenzione di denominazione specifica 1234_TasksCompletedInThisIteration in cui il numero è il numero successivo nel set di script già presenti e il nome descrive cosa viene eseguito in questo check in. Lo faccio in questo modo perché parte del mio processo di compilazione comincio con un nuovo database che viene quindi compilato in modo programmatico utilizzando gli script in questa directory. Ho scritto un task NAnt personalizzato che scorre ogni script eseguendo il suo contenuto sul db bare. Ovviamente se ho bisogno di alcuni dati per andare nel db allora ho anche degli script di inserimento dati. Questo ha anche molti vantaggi. Uno, tutta la mia roba è in versione. Due, ogni build è una build nuova, il che significa che non ci sarà nulla di subdolo nel processo di sviluppo (come i dati sporchi che causano stranezze nel sistema). Tre, quando un nuovo ragazzo viene aggiunto al team di sviluppo, hanno semplicemente bisogno di ottenere l’ultimo e il loro dev locale è costruito per loro al volo. Quattro, posso eseguire test case (non l’ho chiamato “unit test”!) Sul mio database quando lo stato del database viene resettato con ogni build (cioè posso testare i miei repository senza preoccuparmi di aggiungere dati di test al db).

Questo non è per tutti.

Questo non è per ogni progetto. Di solito lavoro su progetti di campi verdi che mi consentono questa comodità!

Piuttosto che entrare in discussioni con la torre bianca, ecco una soluzione che ha funzionato molto bene per me sui problemi del mondo reale.

Costruire un database da zero può essere riassunto come la gestione degli script sql.

DBdeploy è uno strumento che controllerà lo stato corrente di un database, ad esempio quali script sono stati precedentemente eseguiti contro di esso, quali script sono disponibili per essere eseguiti e quindi quali script sono necessari per essere eseguiti.

Quindi raccoglierà tutti gli script necessari ed eseguirli. Quindi registra quali script sono stati eseguiti.

Non è lo strumento più bello o il più complesso, ma con una gestione attenta può funzionare molto bene. È open source e facilmente estensibile. Una volta che l’esecuzione degli script è gestita bene, aggiungere alcuni componenti extra come uno script di shell che controlla gli ultimi script ed esegue dbdeploy su una particolare istanza è facilmente raggiungibile.

Guarda una buona introduzione qui:

http://code.google.com/p/dbdeploy/wiki/GettingStarted

Potresti scoprire che Liquibase gestisce molto di ciò che stai cercando.

Ogni sviluppatore dovrebbe avere il proprio database locale e utilizzare il controllo del codice sorgente per pubblicare nel team. La mia soluzione è qui: http://dbsourcetools.codeplex.com/ Divertiti, – Nathan