Schémas de base de données : migrer sans point de non-retour
Une migration de schéma échoue rarement à cause d’une seule instruction. Le risque vient surtout d’une bascule qui rend simultanément l’ancienne application inutilisable et les nouvelles données difficiles à reprendre.
Article rédigé automatiquement par une intelligence artificielle, à titre informatif. Il peut contenir des imprécisions et ne constitue pas un conseil juridique.
Le scénario est classique : une nouvelle version applicative modifie le schéma, transforme les données puis supprime les anciennes structures pendant la même fenêtre de déploiement. Si l’application présente ensuite une anomalie, remettre le binaire précédent ne suffit plus. Il attend des colonnes qui n’existent plus ou ne comprend pas les nouvelles valeurs. Restaurer la base depuis une sauvegarde est encore autre chose : cette opération peut effacer les transactions enregistrées depuis la bascule et imposer une interruption bien supérieure au retour arrière prévu. Le défaut n’est donc pas seulement technique. Il vient d’un plan qui confond trois opérations différentes : annuler un déploiement, inverser une transformation de données et restaurer un état antérieur.
Le piège de la bascule unique
Une migration fiable commence par supprimer le couplage temporel entre code, schéma et données. Une modification destructive ne devrait pas être nécessaire à l’instant où la nouvelle version démarre. L’ancien et le nouveau code doivent pouvoir cohabiter pendant une période définie, y compris lorsque plusieurs instances applicatives ne sont pas mises à jour exactement au même moment. Cette compatibilité doit être vérifiée, pas simplement affirmée dans un dossier de changement. Il faut notamment tester les versions mixtes, les traitements différés, les tâches planifiées, les outils d’administration et les consommateurs moins visibles de la base. Une colonne apparemment inutilisée peut encore alimenter un export réglementaire, un rapprochement ou un traitement nocturne.
Étendre, migrer, retirer
- Étendre le schéma sans détruire l’existant. Les nouvelles tables, colonnes ou relations sont ajoutées de manière compatible. Les contraintes plus strictes sont introduites seulement lorsque les données les respectent déjà. La durée des verrous, la croissance des journaux, la charge d’entrée-sortie et le retard de réplication doivent être mesurés sur un volume représentatif.
- Déployer un code capable de comprendre les deux formes de données. Lorsque deux écritures sont temporairement nécessaires, elles doivent être idempotentes, observables et réconciliables. Une double écriture sans mécanisme de détection des écarts crée deux vérités concurrentes ; elle déplace le risque au lieu de le réduire.
- Transformer les données par lots limités, reprenables et identifiés par un point de contrôle. Le traitement doit pouvoir s’arrêter sans recommencer depuis le début. Son débit est ajusté selon la charge de production, le retard de réplication et les temps de réponse, plutôt que selon une durée arbitraire de fenêtre.
- Basculer les lectures après validation. Le contrôle ne se limite pas au nombre de lignes : il porte aussi sur les valeurs nulles, les doublons, les relations, les agrégats et les invariants métier. Les écarts doivent être quantifiés et expliqués avant que l’ancienne représentation cesse d’être la référence.
- Retirer l’ancien schéma dans un changement séparé. Cette étape intervient après une période d’observation et après vérification des dépendances réelles. Elle possède son propre plan, ses propres validations et son approbation. Reporter une suppression coûte peu ; supprimer trop tôt transforme une anomalie applicative en incident de données.
Prouver le retour
Le plan de retour doit préciser ce qui revient en arrière. Le code peut-il être redéployé sans modifier les données ? Les écritures produites par la nouvelle version restent-elles lisibles par l’ancienne ? Une transformation inverse existe-t-elle, et conserve-t-elle toute l’information ? Si une restauration est nécessaire, quel point de reprise est acceptable et comment les transactions postérieures seront-elles traitées ? Ces questions appellent des essais sur une copie représentative, avec les mêmes scripts versionnés que ceux destinés à la production. Les critères d’arrêt doivent être observables : taux d’erreur, latence, blocages, retard de réplication, files en attente et écarts de données. Enfin, les preuves d’exécution doivent être conservées : version du schéma, identité des scripts, validations réalisées, décisions de bascule et résultats de réconciliation. Dans une organisation régulée, un changement réussi mais impossible à retracer reste un changement mal maîtrisé.
Toutes les évolutions ne peuvent pas être rendues transparentes. Certaines transformations imposent une fenêtre d’indisponibilité ou une reconstruction lourde. La bonne pratique n’est pas de qualifier artificiellement l’opération de migration sans interruption, mais d’annoncer sa contrainte, de limiter son périmètre et de tester la reprise. Une sauvegarde restaurable demeure indispensable ; elle ne remplace toutefois ni la compatibilité entre versions ni un mécanisme de retour conçu avant la bascule.
The scenario is familiar: a new application release changes the schema, transforms the data and removes the old structures within the same deployment window. If the application then develops a fault, restoring the previous binary is not enough. It expects columns that no longer exist or cannot interpret the new values. Restoring the database from a backup is a different operation again: it may erase transactions recorded since the cutover and require an outage far longer than the planned rollback. The flaw is therefore not merely technical. It comes from a plan that conflates three separate operations: rolling back a deployment, reversing a data transformation and restoring an earlier state.
The single-cutover trap
A reliable migration starts by removing the timing dependency between code, schema and data. A destructive change should not be required at the moment the new release starts. Old and new code must be able to coexist for a defined period, including when several application instances are not updated at precisely the same time. This compatibility must be tested, not merely stated in a change record. Mixed versions, deferred processing, scheduled jobs, administration tools and less visible database consumers all need to be covered. A seemingly unused column may still feed a regulatory export, a reconciliation process or an overnight job.
Expand, migrate, remove
- Expand the schema without destroying what already exists. New tables, columns or relationships are added compatibly. Stricter constraints are introduced only once the data already complies with them. Lock duration, log growth, input-output load and replication lag must be measured against a representative volume.
- Deploy code that can understand both data forms. Where two writes are temporarily required, they must be idempotent, observable and reconcilable. Dual writes without a discrepancy-detection mechanism create two competing sources of truth; they shift the risk rather than reduce it.
- Transform data in bounded, resumable batches identified by checkpoints. Processing must be able to stop without restarting from the beginning. Its throughput is adjusted according to production load, replication lag and response times, rather than an arbitrary maintenance-window duration.
- Switch reads after validation. Checks must cover more than row counts: null values, duplicates, relationships, aggregates and business invariants also matter. Discrepancies must be quantified and explained before the previous representation ceases to be authoritative.
- Remove the old schema through a separate change. This step follows an observation period and verification of actual dependencies. It has its own plan, validation and approval. Postponing removal costs little; removing too early turns an application fault into a data incident.
Proving the rollback
The rollback plan must state exactly what is being reversed. Can the code be redeployed without changing the data? Can the previous release read writes produced by the new one? Does a reverse transformation exist, and does it preserve all information? If restoration is required, what recovery point is acceptable and how will later transactions be handled? These questions require tests on a representative copy, using the same version-controlled scripts intended for production. Abort criteria must be observable: error rate, latency, lock contention, replication lag, queued work and data discrepancies. Execution evidence must also be retained: schema version, script identity, completed validations, cutover decisions and reconciliation results. In a regulated organisation, a successful change that cannot be traced remains a poorly controlled change.
Not every change can be made transparent. Some transformations require an outage window or substantial rebuilding. Good practice is not to label the operation as a zero-downtime migration, but to state its constraint, limit its scope and test recovery. A restorable backup remains essential; however, it replaces neither compatibility between releases nor a rollback mechanism designed before cutover.