Réconciliation des données : prouver que votre migration a fonctionné correctement

Vous venez de terminer une migration de données. Le script s'est exécuté sans erreur. Les logs sont propres. L'équipe est prête à passer à autre chose. Mais au fond de vous, ce doute persiste : tout a-t-il vraiment fonctionné ? Chaque ligne est-elle bien arrivée ? Des valeurs ont-elles été silencieusement corrompues ?

C'est le moment où la plupart des équipes réalisent qu'une migration réussie n'est pas synonyme de migration correcte. Un script peut se terminer avec un code de sortie zéro et pourtant produire des données erronées. Un filtre peut exclure des lignes qu'il aurait dû inclure. Une conversion de type peut tronquer des valeurs sans lever d'erreur. La base de données ne vous signalera pas ces problèmes, sauf si vous les lui demandez explicitement.

C'est pourquoi la réconciliation existe. C'est le processus de comparaison des données avant et après une migration pour prouver que rien n'a été perdu, modifié ou corrompu. C'est le dernier point de contrôle avant de déclarer la migration terminée.

Pourquoi des scripts sans erreur ne suffisent pas

La vérité inconfortable à propos de la migration de données est que l'exactitude et l'exécution sans erreur sont deux choses différentes. Un script de migration peut s'exécuter parfaitement d'un point de vue technique et pourtant produire des résultats incorrects.

Prenons un scénario courant : vous migrez une table avec une clause WHERE qui filtre les utilisateurs inactifs. Le script s'exécute, les lignes sont insérées avec succès, et l'ancienne table est dépréciée. Des semaines plus tard, quelqu'un remarque qu'un groupe d'utilisateurs actifs est manquant. Le filtre était trop agressif, ou la condition était erronée. Le script n'a jamais échoué, mais les données sont fausses.

Les erreurs dans les logs ne capturent pas ce genre de problème. Le moteur de base de données ne sait pas qu'une ligne manquante est une erreur. Il sait seulement que l'instruction INSERT s'est exécutée avec succès. La seule façon de détecter ces échecs silencieux est de comparer directement les données source avec les données cibles.

L'approche pratique de la réconciliation

La réconciliation n'a pas besoin d'être compliquée. La méthode la plus simple et la plus efficace est la comparaison par somme de contrôle (checksum). Au lieu de checksummer des fichiers, vous checksummez des lots de données.

Voici comment cela fonctionne pour une migration de table :

  1. Lire un lot de lignes de la table source.
  2. Calculer un hash du lot entier (par exemple, en utilisant MD5 ou SHA256 sur une concaténation de toutes les valeurs des colonnes).
  3. Lire le même lot depuis la table cible en utilisant le même ordre et calculer le même hash.
  4. Comparer les deux hash.

Si les hash correspondent, le lot est identique. Sinon, vous savez exactement quel lot pose problème et vous pouvez enquêter sur cette plage spécifique de lignes.

Pour les grandes tables, le traitement par lots est essentiel. Vous ne voulez pas charger des millions de lignes en mémoire d'un coup. Une taille de lot de 1 000 à 10 000 lignes fonctionne bien pour la plupart des bases de données. Vous pouvez exécuter ces comparaisons en parallèle sur plusieurs lots pour accélérer le processus.

Le diagramme suivant illustre le processus de réconciliation lot par lot :

flowchart TD A[Début] --> B[Extraire un lot de la table source] B --> C[Calculer le hash du lot] C --> D[Extraire le même lot de la table cible] D --> E[Calculer le hash du lot] E --> F{Comparer les hash} F -- Correspondent --> G[Marquer le lot comme vérifié] F -- Ne correspondent pas --> H[Signaler le lot pour investigation] G --> I[Autres lots ?] H --> I I -- Oui --> B I -- Non --> J[Comparer les comptages de lignes] J --> K{Comptages identiques ?} K -- Oui --> L[Générer le rapport : migration vérifiée] K -- Non --> M[Signaler l'écart et enquêter] L --> N[Fin] M --> N

Voici une requête SQL concrète qui implémente cette approche pour deux tables :

-- Compare les comptages de lignes et les sommes de contrôle entre les tables source et cible
WITH source_checksums AS (
    SELECT
        COUNT(*) AS row_count,
        MD5(STRING_AGG(CAST(column1 AS TEXT) || '|' || CAST(column2 AS TEXT) || '|' || CAST(column3 AS TEXT), ',' ORDER BY id)) AS batch_hash
    FROM source_table
),
target_checksums AS (
    SELECT
        COUNT(*) AS row_count,
        MD5(STRING_AGG(CAST(column1 AS TEXT) || '|' || CAST(column2 AS TEXT) || '|' || CAST(column3 AS TEXT), ',' ORDER BY id)) AS batch_hash
    FROM target_table
)
SELECT
    'Écart de comptage de lignes' AS issue
FROM source_checksums, target_checksums
WHERE source_checksums.row_count <> target_checksums.row_count
UNION ALL
SELECT
    'Écart de somme de contrôle' AS issue
FROM source_checksums, target_checksums
WHERE source_checksums.batch_hash <> target_checksums.batch_hash;

Cette requête calcule une somme de contrôle unique sur toutes les lignes de chaque table (en utilisant un ordre stable) et compare à la fois le nombre de lignes et le hash. Si l'un des deux diffère, la requête renvoie une indication claire de ce qui a mal fonctionné.

Quoi d'autre vérifier au-delà des sommes de contrôle

Les sommes de contrôle détectent la plupart des problèmes, mais ce n'est pas la seule chose à vérifier. Quelques contrôles supplémentaires renforcent la confiance sans beaucoup d'effort supplémentaire.

Comptage de lignes. C'est le contrôle le plus simple. Le nombre de lignes dans la table cible doit correspondre au nombre de lignes dans la table source. Si les comptages diffèrent, quelque chose a mal fonctionné dans la logique de migration.

Valeurs NULL. Les migrations modifient parfois des colonnes NULL en valeurs par défaut ou vice versa. Comparez le nombre de NULL par colonne entre la source et la cible. Un écart ici indique souvent un problème de conversion de type ou une contrainte de valeur par défaut appliquée incorrectement.

Distribution des valeurs. Choisissez quelques colonnes importantes et comparez leurs distributions de valeurs. Par exemple, si la table source a 1 000 utilisateurs avec le statut "actif" et 500 avec le statut "inactif", la table cible doit avoir les mêmes nombres. Une différence significative suggère un bug dans le filtre de migration ou la logique de transformation.

Cas particuliers. Testez des lignes spécifiques connues pour être délicates : lignes avec des caractères spéciaux, des chaînes très longues, des dates proches des limites, ou des nombres négatifs. Si votre migration a géré celles-ci correctement, c'est un bon signe que la logique générale est saine.

Intégrer la réconciliation dans votre pipeline

La réconciliation ne doit pas être une tâche manuelle ponctuelle dont quelqu'un se souvient après une migration tardive. Elle doit être automatisée et intégrée dans votre pipeline de déploiement.

Écrivez un script de réconciliation qui s'exécute après les étapes de migration et de backfill. Le script doit :

  • Se connecter aux bases de données source et cible.
  • Exécuter la comparaison par lots avec somme de contrôle.
  • Vérifier les comptages de lignes, les comptages de NULL et les distributions de valeurs.
  • Générer un rapport détaillé de toute divergence.
  • Envoyer une notification (email, Slack, ou tout autre outil utilisé par votre équipe) avec les résultats.

Si la réconciliation réussit, le pipeline peut passer à l'étape suivante. Si elle échoue, le pipeline doit s'arrêter et alerter l'équipe. Cela empêche des données incorrectes d'atteindre la production sans que personne ne le remarque.

Automatiser la réconciliation la rend également reproductible. Chaque migration passe par le même processus de vérification. Vous n'avez pas à compter sur quelqu'un qui se souvient d'exécuter un script ou de vérifier les bonnes choses. Le pipeline l'impose.

Ce que la réconciliation n'est pas

La réconciliation ne remplace pas les tests à blanc (dry runs) ou les stratégies de backfill. Chaque étape a un objectif différent.

  • Les tests à blanc vérifient que la logique de migration fonctionne sans affecter les données de production.
  • Le backfill gère le transfert de données réel en lots gérables pour minimiser l'impact.
  • La réconciliation prouve que le backfill a produit des résultats corrects.

Considérez la réconciliation comme la porte de qualité finale. Elle confirme que toutes les étapes précédentes ont fonctionné comme prévu. Si la réconciliation réussit, vous pouvez être confiant que les données sont prêtes. Si elle échoue, vous revenez en arrière, corrigez le problème et relancez la migration depuis le début.

Une checklist pratique pour la réconciliation

Lorsque vous mettez en place la réconciliation pour votre prochaine migration, voici une courte checklist pour vous guider :

  • Comparaison par somme de contrôle par lot (1 000 à 10 000 lignes par lot)
  • Correspondance du nombre de lignes entre source et cible
  • Correspondance du nombre de NULL par colonne
  • Correspondance de la distribution des valeurs pour les colonnes clés
  • Vérification des cas particuliers (caractères spéciaux, valeurs limites)
  • Script automatisé intégré dans le pipeline
  • Notification en cas d'échec avec un rapport détaillé des écarts

L'essentiel à retenir

Une migration n'est pas terminée tant que vous n'avez pas prouvé que les données sont correctes. Une exécution sans erreur ne suffit pas. La réconciliation vous apporte cette preuve en comparant directement les données source et cible. Automatisez-la, exécutez-la à chaque fois, et traitez un échec de réconciliation comme vous traiteriez un test échoué : arrêtez-vous, enquêtez et corrigez avant de continuer.