Quels sont les moyens efficaces de gérer les schémas de base de données partagés entre les branches de code?


12

Travailler sur un projet avec plusieurs branches, où chaque branche est finalement fusionnée à la branche principale, et est essentiellement isolée afin de développer une nouvelle fonctionnalité.

La base de données, qui est MS SQL Server, a un schéma partagé, mais chaque branche modifie le schéma au fur et à mesure de sa progression.

Ma principale question est de savoir quelles sont les bonnes façons de gérer le partage du schéma de la branche principale vers la branche dérivée, de sorte que les modifications apportées à la branche principale soient facilement fusionnées dans la branche dérivée, sans s'appuyer sur de nouvelles modifications dans la dérivée. branche?


2
La fusion doit être gérée comme n'importe quel autre code: fusion automatique, avec intervention de l'utilisateur, et inspection / test du résultat. (Je préfère la façon dont le projet VS Database gère les schémas avec un objet par fichier.). Le plus délicat vient du fonctionnement des migrations directes des bases de données existantes ;-)

2
Cela dépend fortement de la façon dont vous versionnez le schéma. Stockez-vous des scripts de création pour les objets de base et des scripts de modification? Utilisez-vous un outil de comparaison de schémas pour générer des scripts alter pour migrer entre les versions? Projets de base de données VS2010?
Mark Storey-Smith,


1
Également pertinent: martinfowler.com/articles/…
Nick Chammas

Réponses:


7

J'ai utilisé avec succès la méthodologie suivante, élaborée dans Version Control et votre base de données :

  • maintenir un numéro de version dans les métadonnées (j'utilise une propriété étendue de base de données)
  • tout changement de schéma est codé comme un script qui met à jour de la version actuelle vers la version suivante
  • l'application est livrée avec tous les scripts pour passer de la version 0 (déploiement initial) à la version actuelle
  • Chaque changement est effectué via un script. Y compris les modifications des données «système» comme les dictionnaires et les entrées de table de recherche.
  • une fois déployée, l'application vérifie la version du schéma sur disque, puis exécute toutes les étapes de mise à niveau pour amener le schéma à la version requise actuelle

J'entends souvent l'opinion de «en quoi est-ce différent de simplement garder les scripts de définition d'objet sous contrôle de source?». La différence est énorme, car lorsque vous déployez une nouvelle version de votre application, vous n'allez pas simplement créer une nouvelle base de données. La plupart du temps, votre application devra mettre à niveau la base de données existante, y compris les données existantes . Il s'agit d'une différence cruciale, vos étapes de mise à niveau doivent garantir l'intégrité et la cohérence des données existantes pendant la mise à niveau. Certaines opérations sont triviales dans le code (ajoutez une colonne non nullable avec une valeur par défaut au script de définition d'objet de table, c'est fait), mais elles sont en fait extrêmement douloureuses lors du déploiement réel (la table a 1,5 milliard de lignes, la colonne d'ajout s'épuiserait de l'espace de journal si cela est fait de la manière «simpleton»).

Comment cela fonctionne avec la ramification:

  • lorsque la branche est créée, elle capture la version actuelle du schéma, par exemple la version 1.6
  • lorsque l'équipe commence à travailler sur la branche, elle ajoute une nouvelle version, 1.7, puis commence à coder l'étape de mise à niveau de 1.6 à 1.7
  • l'étape de mise à niveau est modifiée à mesure que les modifications sont effectuées dans la branche. Il exécute toujours le script de mise à niveau de la version 1.6 vers la version 1.7, mais ce que font exactement ces scripts est soumis aux itérations de code normales et aux enregistrements dans la branche
  • la branche termine le développement, elle se prépare à l'intégration inverse (à fusionner de nouveau dans la ligne de base)
    • il fait une nouvelle intégration directe de la ligne de base à la branche. Si l'intégration n'apporte aucun changement à la version du schéma, tout va bien, la branche peut inverser l'intégration telle quelle. la version 1.7 devient la nouvelle version de base.
    • le truc intéressant, c'est quand une autre branche a inversé l'intégration dans la base entre-temps et maintenant la version du schéma de base est devenue, disons, 1.7. Dans ce cas, notre branche doit faire passer sa version de schéma cible de déploiement à 1.8 et passer en revue l'étape de mise à niveau qui était auparavant de 1.6 à 1.7 pour voir comment elle fonctionne dans le nouvel environnement, passant de 1.7 à 1.8. Les conflits de schéma logique doivent être résolus, le script peut nécessiter des modifications, des tests doivent être effectués. Une fois terminée, la branche peut inverser l'intégration dans la base. La version cible déployée du produit devient désormais la version 1.8.
    • lorsqu'une autre branche qui a bifurqué à la version 1.6 du schéma veut procéder à une intégration inversée, elle doit faire passer sa version de schéma à 1.9, tester le script de mise à niveau de 1.8 à 1.9, puis il peut réintégrer la base.

Notez qu'aucun outil n'est impliqué, aucun script de différence de schéma magique, aucun assistant et aucun script de clic droit-générer-impliqué. Il s'agit d'un processus 100% axé sur les développeurs, basé sur la source (scripts). Beaucoup trouvent tout ce processus complexe, mais cela fonctionne. En fait, en tant qu'utilisateur SQL Server, vous avez déjà tiré parti des résultats de ce processus dans votre utilisation quotidienne de SQL Server: SQL Server lui-même utilise un processus de mise à niveau de base de données très similaire et, comme vous vous en doutez probablement, le processus de développement de produits fait un usage intensif de ramification et le problème que vous avez mentionné est un problème très réel qui doit être résolu.

BTW, comment la ramification / intégration se produit réellement diffère entre les produits de contrôle de source, j'utilise les termes familiers du mode de fonctionnement d' intégration forcée .


+1, en particulier pour chaque changement se fait via un script
a_horse_with_no_name

1

Bien que ma réponse ne soit pas aussi longue que celle de Remus, j'ai trouvé que c'était une très bonne solution. Je ne l'ai pas encore mis en production, donc YMMV *.

Liquibase

Il s'agit essentiellement d'un fichier XML dans lequel vous apportez des modifications de schéma à votre base de données en tant que nouveaux éléments dans le fichier XML. Par exemple:

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

Il a une syntaxe entièrement étoffée afin que vous puissiez faire à peu près tout ce que vous voulez dans votre base de données.

Vous spécifiez également dans votre installation Liquibase la base de données que vous souhaitez versionner. Ensuite, vous "exécutez" le .xml avec l'exécutable Java inclus (fichier jar). Cela recrée essentiellement les modifications spécifiées dans le XML dans votre base de données.

Le vrai truc, c'est que vous stockez ce fichier XML dans le même dossier versionné que votre code. Donc, dans mon cas, c'était Git. J'avais ce fichier XML dans mon dossier de projet (même niveau que /.git), puis chaque fois que je changeais de branche, le fichier XML passait à cette version de branche et j'exécutais le fichier .jar et ma base de données reflétait maintenant cette branche.

* Remarque: je n'ai pas terminé l'implémentation car j'ai eu du mal à connecter Java à SQL Server. A besoin de pilotes jdbc et autres et je n'étais pas d'humeur. Par conséquent, votre kilométrage peut varier.


1

Chez Red Gate, nous publions bientôt une solution de gestion des versions de base de données qui exploite à la fois la comparaison SQL et le contrôle de source SQL. Cela utilise une approche de mise à niveau des scripts de migration et marque la base de données avec une propriété étendue de version qui correspond à une révision du contrôle de code source.

Nous espérons sortir à la mi-décembre. Un candidat à la sortie est disponible dès maintenant. Pour plus d'informations, visitez:

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

Nous espérons tirer parti de cette solution dans les mois à venir, alors faites-nous savoir ce que vous en pensez.


0

Si vous et la gestion de vos modifications de schéma en générant des scripts et en gardant ces scripts sous contrôle de source, vous devriez être en mesure de traiter les modifications comme vous le feriez pour n'importe quel autre code. Vous pouvez choisir de fusionner automatiquement ou d'intervenir plus manuellement.


Non, pas vraiment. La fusion manuelle des scripts de création d'objet de base est viable mais modifiez, les insertions de données de référence et les scripts de mouvement de données deviennent très désordonnés, très rapidement.
Mark Storey-Smith,

D'accord. Chez Red Gate, nous pensons que les scripts de création fusionneront assez bien et pourraient être automatisés. Cependant, les scripts de migration entre les versions devront être fusionnés manuellement pour éviter un ordre de dépendance incorrect et la duplication du code de modification.
David Atkinson

0

Je suis dans une situation similaire où je travaille sur un site Web en direct et plusieurs branches de développement dans lesquelles je dois changer le schéma de la base de données.

Je l'ai résolu en écrivant un post-checkout et un hook post-fusion qui peuvent être bien utilisés avec git. Je stocke toutes mes migrations sous forme de fichiers SQL dans un répertoire séparé et les valide avec le code PHP modifié. Chaque fois que j'exécute un

git checkout

ou un

git merge

git appellera automatiquement les migrations ascendantes et descendantes appropriées. Voir mon implémentation sur Github .

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.