La migration de schéma de base de données figure parmi les opérations les plus stressantes pour les équipes techniques. Un changement mal géré peut provoquer l’interruption du service, la perte de données ou des bugs critiques en production. Pourtant, faire évoluer le schéma est inévitable dans toute application vivante. Heureusement, des méthodes éprouvées permettent de minimiser drastiquement les risques et de dormir tranquille pendant les déploiements.
Sommaire
Comprendre les risques d’une migration
Avant d’aborder les solutions, identifions les dangers. Une migration peut échouer techniquement, prendre plus de temps que prévu et bloquer la base, ou créer une incompatibilité entre le nouveau schéma et le code encore en cours d’exécution. Le plus insidieux : la migration réussit, mais introduit des bugs silencieux découverts des jours plus tard.
Les bases de production contiennent souvent des millions de lignes. Une simple modification de colonne peut nécessiter la réécriture complète d’une table, opération potentiellement longue qui verrouille les écritures. Pendant ce temps, votre application est inaccessible. C’est précisément ce scénario qu’il faut éviter à tout prix.
La stratégie des migrations réversibles

Toujours prévoir le rollback
La première règle d’or : chaque migration doit posséder une migration inverse testée. Si la version 42 ajoute une colonne, vous devez avoir une migration de rollback qui la supprime proprement. Cette discipline impose de réfléchir à la réversibilité dès la conception.
Certaines migrations sont naturellement irréversibles (suppression de colonne avec données). Dans ces cas, documentez clairement l’impossibilité du rollback et mettez en place des sauvegardes complètes avant l’opération. Mieux encore, utilisez une stratégie par étapes qui conserve temporairement les anciennes structures. Découvrez toutes les informations en cliquant ici.
Tester sur des données réalistes
Tester une migration sur une base vide ou avec cent lignes ne révèle rien. Créez un environnement de staging avec une copie anonymisée de la production, ou au minimum un jeu de données de plusieurs millions de lignes. Mesurez le temps d’exécution et observez les verrous générés.
Cette étape révèle souvent que votre migration « instantanée » prendra en réalité quinze minutes en production, information cruciale pour planifier une fenêtre de maintenance.
Les techniques de migration sans interruption
L’approche expand-contract
La méthode expand-contract (ou expand-migrate-contract) permet de migrer sans downtime en trois phases distinctes :
Phase 1 – Expand : ajoutez les nouvelles structures (colonnes, tables) sans supprimer les anciennes. Déployez le code qui écrit dans les deux structures. À ce stade, ancien et nouveau schéma coexistent.
Phase 2 – Migrate : copiez progressivement les données de l’ancien vers le nouveau format, par petits lots (batches). Cette étape peut prendre des heures ou des jours sans affecter la disponibilité.
Phase 3 – Contract : une fois toutes les données migrées et le nouveau code stabilisé, supprimez les anciennes structures devenues obsolètes.
Cette approche nécessite au minimum deux déploiements distincts, mais élimine tout risque d’interruption.
Les migrations par lots progressifs
Pour les modifications de données massives, évitez les transactions monolithiques qui verrouillent la table. Utilisez des batchs de 1000 à 10000 lignes avec de courtes pauses entre chaque lot.
Cette technique maintient la base réactive pour les autres opérations et permet d’interrompre proprement la migration en cas de problème. PostgreSQL propose LIMIT et OFFSET, MySQL utilise LIMIT avec des curseurs, et tous supportent les mises à jour par lots.
Les outils de migration online
Des outils spécialisés facilitent les migrations complexes. gh-ost et pt-online-schema-change pour MySQL permettent de modifier des tables massives sans verrous prolongés en créant une table fantôme, en y copiant les données progressivement via des triggers, puis en effectuant un basculement atomique.
PostgreSQL supporte nativement certaines opérations non-bloquantes comme ADD COLUMN avec valeur par défaut (depuis la version 11), évitant la réécriture complète de la table.
La gestion des versions de schéma
Outils de versioning
Ne gérez jamais les migrations manuellement. Utilisez des outils dédiés : Flyway, Liquibase, Alembic (Python), migrate (Go), ou les migrations intégrées à votre framework (Django, Rails, Laravel).
Ces outils garantissent que les migrations s’appliquent dans le bon ordre, une seule fois, et maintiennent l’historique des changements dans une table de métadonnées. Ils transforment les migrations en processus déterministe et reproductible.
Nommage et documentation
Nommez vos migrations de manière explicite : 20260113_add_user_email_verification_column.sql plutôt que migration_042.sql. Documentez le contexte métier et les dépendances entre migrations. Votre vous du futur vous remerciera.
Les points de vigilance critiques
Méfiez-vous des contraintes d’intégrité ajoutées sur des données existantes. Valider une contrainte NOT NULL ou UNIQUE sur des millions de lignes peut échouer à mi-parcours. Nettoyez d’abord les données, vérifiez la faisabilité, puis ajoutez la contrainte.
Les indexes sur de grandes tables prennent du temps. Sur PostgreSQL, utilisez CREATE INDEX CONCURRENTLY qui évite les verrous d’écriture. Attention : cette commande ne peut s’exécuter dans une transaction.
La migration de schéma n’est pas une opération à prendre à la légère, mais avec méthode, tests rigoureux et déploiements progressifs, elle devient une routine maîtrisée plutôt qu’une source d’anxiété nocturne.
