Votre extraction de factures donne le même nombre de lignes après une mise à jour. Le traitement se termine sans erreur. Est-ce suffisant pour diffuser le reporting ? Une partition peut manquer, un doublon peut remplacer une autre ligne et un montant peut avoir changé d’unité.
DuckDB 1.5.6, publiée le 28 septembre 2026, fournit une bonne occasion de construire une recette de non-régression sur vos fichiers. Ce guide explique les corrections utiles et propose un atelier local : dix lignes fictives, un passage de CSV à Parquet, puis quatre anomalies volontaires. L’objectif est de décider si un résultat peut continuer à alimenter un indicateur.
La recette a été exécutée le 12 octobre 2026 avec DuckDB 1.5.6 et Python 3.14.7 sur macOS arm64. Le fichier témoin passe les contrôles ; les quatre anomalies sont détectées. Ce test ne mesure ni la vitesse sur vos volumes ni le comportement d’une version précédente.
Ce qui change dans DuckDB 1.5.6
DuckDB est un moteur SQL analytique utilisable directement dans un processus, notamment Python. Il peut lire des fichiers sans chargement préalable dans un entrepôt. Dans cet article, il sert à contrôler un export local ; aucun service cloud n’est nécessaire. Présentation du projet.
La release du 28 septembre contient des correctifs, notamment sur certains résultats de UNION ALL, sur des opérations Parquet et sur les valeurs NULL dans certaines optimisations de fenêtres. Ce sont des cas précis. Cela ne signifie pas que toutes les requêtes de la branche 1.5 donnaient des résultats faux.
Un correctif mérite une attention particulière pour les équipes qui lisent des dossiers partitionnés : MAX sur une colonne de partition Hive après élimination de fichiers. Le ticket #25766 décrit un crash ou une assertion lorsque le filtre ne laisse qu’un fichier Parquet. Le nom du dossier porte la valeur de partition ; cette colonne n’occupe pas nécessairement une place dans le schéma interne du fichier.
La décision pratique consiste à repérer vos requêtes concernées, puis à vérifier leurs résultats dans un environnement isolé. Une note de version aide à choisir les tests. Elle ne remplace pas votre référence métier.
Version stable, LTS et nouveautés 2.0 : trois décisions distinctes
Au 12 octobre, la documentation Python indique 1.5.6 comme version stable. Le calendrier officiel prévoit 2.0.0 pour le 21 octobre 2026, avec une date explicitement provisoire. Une équipe déjà sur une branche LTS doit examiner son propre cycle de support avant de changer de branche.
Le mode agent de la CLI, annoncé le 9 octobre pour la 2.0, concerne la lecture des sorties par des agents IA : présentation compacte et troncatures explicites, notamment. Il ne fait pas partie de l’atelier 1.5.6. L’expérience publiée par DuckDB réduit les tokens des sorties lues, mais pas le coût total ni la durée de cet essai. Ne transformez pas cette annonce en promesse d’économie globale. Annonce du mode agent.
La recette proposée ici reste utile sans agent IA et sans migration immédiate vers 2.0.
Pourquoi vérifier davantage qu’une somme
Prenons un cas fictif : un service finance reçoit un CSV de factures, le convertit en Parquet et calcule une ventilation par pays. Son contrôle courant consiste à comparer le total avant et après conversion.
Ce rapprochement détecte certaines pertes de données. Il laisse pourtant passer une erreur présente des deux côtés. Si une facture de 100,10 euros arrive sous la valeur 10 010,00, la conversion peut être parfaitement fidèle. Les fichiers concordent ; l’unité est fausse.
Il faut donc deux références :
- Une référence de transport : les lignes, les types et les valeurs ont-ils survécu à la lecture et à l’écriture ?
- Une référence métier indépendante : les clés, unités, périodes et montants correspondent-ils à ce qui est attendu ?
Dans notre atelier, la première comparaison accepte les scénarios « doublon » et « centimes » parce que l’erreur est copiée correctement. Les contrôles métier les refusent. Cette distinction complète notre guide sur les data contracts : un schéma valide ne suffit pas à établir le sens d’un montant.
Trois cas d’usage pour une équipe data française
Contrôler un export avant une clôture. L’entrée est un fichier figé, accompagné de la période et des totaux de contrôle fournis par la source. La décision porte sur sa diffusion. Le résultat attendu est un rapprochement signé : clés uniques, montants connus, valeurs absentes et écarts par entité. Limite : un total de référence calculé par la même requête peut reproduire la même erreur. Faites valider la définition par le propriétaire de l’indicateur.
Faire évoluer un traitement de fichiers partitionnés. L’entrée est un ensemble de dossiers, par exemple annee=2026/mois=9/. La décision porte sur l’usage d’une nouvelle version du moteur. Le critère de succès couvre chaque partition attendue, les filtres de période et les agrégations finales. Le nom d’un dossier ne prouve pas que tous les fichiers attendus y sont arrivés.
Diagnostiquer un écart entre deux rapports. Figez les extractions des deux rapports, puis comparez les lignes qui entrent dans le calcul. Le livrable est une liste d’écarts explicables : doublons, dates, exclusions, remboursements. DuckDB peut aider à examiner les fichiers. La définition commune du chiffre reste un travail de modélisation et de gouvernance.
Ces trois cas sont des illustrations, pas des missions clients ni des gains mesurés.
Tutoriel : exécuter la recette CSV et Parquet
Téléchargez les fichiers suivants dans un même dossier : recette.py, factures.csv et requirements.txt. Le mode d’emploi précise les limites.
1. Isoler l’installation
Il faut Python 3.10 ou plus récent et un accès au dépôt de paquets pour l’installation. Ensuite, le script n’utilise que des fichiers locaux.
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python recette.py > resultat.json
Sous Windows, remplacez .venv/bin/python par .venv\Scripts\python.exe. La dépendance est fixée à duckdb==1.5.6. Vérifiez la version dans le JSON produit, plutôt que de supposer que la commande duckdb du terminal utilise le même moteur.
Le script crée sa base en mémoire et ses fichiers Parquet dans un dossier temporaire unique. Il ferme la connexion et nettoie les fichiers temporaires à la fin. Il ne modifie pas le CSV téléchargé. Conservez resultat.json comme preuve, puis supprimez le dossier de l’atelier lorsque vous n’en avez plus besoin.
2. Lire le CSV avec un contrat explicite
Le fichier utilise un point-virgule, une virgule décimale et des identifiants avec des zéros initiaux. L’atelier fixe ces choix au lieu de les laisser dépendre de l’échantillon analysé :
SELECT * FROM read_csv('factures.csv',
auto_detect = false,
header = true,
delim = ';',
decimal_separator = ',',
nullstr = '',
columns = {
'facture_id': 'VARCHAR',
'date_facture': 'DATE',
'pays': 'VARCHAR',
'montant_eur': 'DECIMAL(12,2)'
});
VARCHAR conserve 0001. Le décimal fixe évite d’exprimer ce montant monétaire en flottant. Une cellule vide devient NULL ; 0,00 reste zéro. Ces paramètres sont documentés dans la référence CSV. L’atelier n’active pas l’option qui ignore les erreurs de lecture.
3. Définir les résultats attendus avant de les calculer
Pour les dix lignes fictives fournies, la référence est la suivante :
| Contrôle |
Attendu |
| Lignes et identifiants distincts |
10 et 10 |
| Montants absents |
1 |
| Montants égaux à zéro |
1 |
| Somme des montants connus |
500,00 EUR |
| Ventilation France / Allemagne |
400,00 / 100,00 EUR |
| Septembre / octobre |
5 lignes et 210,00 / 5 lignes et 290,00 EUR |
Les 500,00 euros ne sont pas un total facturé complet : une facture a un montant inconnu. La recette vérifie que cette absence reste visible. Elle n’autorise pas sa diffusion comme chiffre d’affaires complet. Pour vos propres données, définissez explicitement si une valeur manquante doit bloquer le reporting.
4. Écrire, relire et comparer les lignes
Le script ajoute l’année et le mois, écrit deux partitions Parquet, puis les relit avec hive_partitioning = true. DuckDB sait récupérer les clés de partition dans les noms de dossiers et utiliser un filtre de période pour éviter des fichiers inutiles. Partitionnement Hive.
La comparaison utilise EXCEPT ALL dans les deux sens. Le mot ALL compte : il conserve les occurrences répétées. Une simple comparaison d’ensembles peut effacer la différence entre une ligne et deux copies de cette ligne.
Le script conserve aussi la liste des fichiers effectivement lus. La lecture Parquet accepte des listes explicites et des motifs de chemins. En production, associez cette liste à un inventaire des fichiers attendus. Un motif qui trouve des fichiers ne prouve pas qu’il les trouve tous.
Enfin, la requête suivante vérifie une agrégation sur une partition filtrée :
SELECT max(mois) FROM relu WHERE mois = 9;
Le résultat observé est 9. Le plan enregistré indique la lecture d’un fichier sur deux. Ce contrôle couvre une situation proche du correctif Hive cité plus haut ; ce n’est pas une reproduction exacte du ticket ni la démonstration d’un échec sur 1.5.5.
5. Vérifier que les contrôles détectent réellement une anomalie
L’atelier rejoue ensuite quatre variantes :
| Anomalie injectée |
Observation avec 1.5.6 |
| Duplication de la première facture |
CSV et Parquet concordent ; référence métier refusée |
| 100,10 remplacé par 10 010,00 |
Conversion valide ; total de référence refusé |
| Partition d’octobre omise de la liste de lecture |
Écart de lignes et de montants détecté |
| Texte « inconnu » dans un montant |
Lecture interrompue par une erreur de conversion |
success: true signifie que les cinq scénarios ont le comportement attendu, dont le refus des quatre variantes anormales. Consultez accepted pour chaque scénario. Copier uniquement le booléen global dans un contrôle de production serait une erreur.
Passer de l’atelier à une décision de migration
Choisissez une extraction représentative et figée, avec l’autorisation de l’utiliser localement. Gardez son empreinte, la liste des fichiers, la version du moteur, les paramètres et la requête. Exécutez la même recette dans deux environnements séparés : votre version actuelle, puis la candidate.
Commencez par la justesse : types, multiplicité des lignes, valeurs absentes, montants, dates et partitions. Une différence n’est pas automatiquement une régression ; elle peut révéler un ancien résultat erroné. Rapprochez-la de la référence métier et du correctif concerné avant d’autoriser la diffusion.
Mesurez ensuite le temps de bout en bout, la mémoire maximale, l’espace temporaire et, pour des données distantes, les lectures et transferts facturés. Répétez les essais sur la même machine en distinguant cache froid et cache chaud. Un jeu de dix lignes ne permet aucune conclusion sur ces métriques.
Le moteur est distribué sous licence MIT. L’atelier n’a pas de coût d’API ni de licence logicielle à acheter. Restent le poste, le stockage et le temps de maintenance ; un service hébergé ou un accès cloud aurait ses propres tarifs.
Limites à garder dans la décision
DuckDB peut utiliser du disque temporaire pour certaines opérations dépassant la mémoire. Cela ne supprime pas toutes les causes d’échec mémoire, notamment avec certaines agrégations ou plusieurs opérations lourdes combinées. Le réglage de 512 MB dans la recette sert uniquement à encadrer ce petit exercice. Limites et réglages des traitements.
Un fichier DuckDB local n’est pas non plus un entrepôt partagé à déployer par simple copie. En mode intégré, la concurrence documentée distingue un processus en lecture-écriture et plusieurs processus en lecture seule sans écrivain. Les besoins de collaboration, de droits et de disponibilité doivent être traités dans l’architecture choisie.
Conservez votre chaîne BI ou votre entrepôt lorsqu’ils portent déjà les règles communes, les accès et la diffusion. Utilisez cette recette pour vérifier une étape de fichiers ou préparer une évolution ciblée. Si vos transformations sont pilotées par dbt, notre décryptage dbt pour les équipes data traite une autre décision : compilation, tests métier et modes d’exécution.
Le premier livrable utile est modeste : un résultat attendu, un écart expliqué et une règle qui bloque la diffusion lorsque le contrôle échoue.