DuckDB pour l'analytique ad hoc : Transformer des milliers de CSV en tableau de bord
Amazon Seller Central génère des données à un rythme qui dépasse l'outillage de la plupart des analystes. Rapports de trafic, données de conversion, résumés de santé des stocks, exports de performance commerciale, ventilations des campagnes publicitaires – chacun livré sous forme de fichier CSV ou TSV, s'accumulant sur des mois et des années dans des répertoires contenant des milliers de fichiers. La réponse standard est d'importer tout dans une base de données. Mais en réalité, monter, maintenir et interroger une instance PostgreSQL pour ce qui est fondamentalement une charge analytique principalement en lecture et à schéma variable introduit plus de surcharge opérationnelle que le problème lui-même ne le justifie.
Nous avons construit un pipeline de reporting pour un vendeur Amazon opérant sur cinq marketplaces européennes. Les données brutes : six ans d'exports Seller Central, 4 200 fichiers, couvrant les rapports commerciaux, les performances publicitaires, les instantanés de stocks et les grands livres de frais FBA. L'approche initiale – un schéma PostgreSQL avec des scripts ETL – a pris trois semaines à stabiliser et a nécessité une attention constante au fur et à mesure qu'Amazon révisait les noms de colonnes et les structures de rapports entre les versions d'API. Les requêtes étaient rapides. La maintenance ne l'était pas.
DuckDB change ce calcul. C'est une base de données analytique embarquée – elle s'exécute en cours de processus aux côtés de votre code d'analyse, ne nécessite pas de serveur, pas de démon, pas de chaînes de connexion, et lit directement depuis les fichiers sur disque. L'interface de requête est du SQL standard. Les caractéristiques de performance sont celles d'un moteur columnaire optimisé pour l'agrégation à grande échelle. Pour une charge de travail comme celle-ci, DuckDB n'est pas juste adéquat – c'est l'outil correct.
Ce qu'est réellement DuckDB
La distinction qui importe le plus est le stockage en colonnes versus le stockage en lignes. PostgreSQL organise les données en lignes : chaque champ pour un enregistrement donné est stocké contiguëment sur disque. Lorsque vous exécutez SELECT revenue, units_sold FROM orders WHERE marketplace = 'DE', la base de données lit chaque champ pour chaque ligne, rejette ceux que vous n'avez pas demandés, et retourne les deux que vous avez demandés. C'est efficace pour les charges transactionnelles – insertion, mise à jour et récupération d'enregistrements individuels. C'est en grande partie inadapté aux requêtes analytiques qui agrègent sur des millions de lignes tout en ne touchant qu'une poignée de colonnes.
DuckDB organise les données par colonne. Chaque valeur pour revenue est stockée ensemble ; chaque valeur pour units_sold est stockée ensemble. La même requête ne lit que les deux blocs de colonnes dont elle a besoin, sautant le reste entièrement. Sur un ensemble de données avec quarante colonnes, ce n'est pas une optimisation mineure – cela réduit les E/S d'environ 95 % pour les requêtes analytiques typiques. Combiné avec l'exécution vectorisée – traitement des données par lots de 1 024 valeurs à la fois en utilisant les instructions CPU SIMD plutôt qu'une ligne à la fois – DuckDB atteint des performances de requête sur les charges analytiques qui dépassent régulièrement ce qu'une instance PostgreSQL bien réglée peut livrer sur du matériel identique.
L'architecture embarquée est tout aussi importante. Il n'y a pas d'aller-retour réseau, pas de surcharge d'authentification, pas de pool de connexions à gérer. DuckDB ouvre un fichier ou un répertoire, construit un plan de requête et s'exécute. Le binaire pèse moins de 100 Mo. Il s'exécute sur un laptop, dans une fonction Lambda, ou dans un script Python invoqué depuis un cron job. Pour les pipelines analytiques auto-hébergés, la surface opérationnelle est proche de zéro.
SQL directement sur des fichiers
La fonctionnalité qui rend DuckDB pratique pour les données Seller Central spécifiquement est le scan de fichiers basé sur glob. Une seule instruction SQL interroge des milliers de CSV simultanément :
SELECT
date_trunc('month', "Date") AS month,
SUM("Units Ordered") AS units,
SUM("Ordered Product Sales") AS revenue
FROM read_csv_auto('/data/seller-central/business-reports/*.csv')
GROUP BY 1
ORDER BY 1;
read_csv_auto infère le schéma à partir du contenu des fichiers – il échantillonne les lignes, détecte les types de colonnes, gère les différents délimiteurs et fusionne les schémas entre les fichiers où les ensembles de colonnes diffèrent. Pour les données Seller Central, où Amazon a révisé les noms de colonnes au moins quatre fois au cours des trois dernières années, c'est important. La requête s'exécute sur tous les fichiers qui existent dans le répertoire au moment de l'exécution, sans étape d'importation, sans migration de schéma, et sans cache périmé à invalider.
Pour les exports TSV de la console publicitaire, la même approche s'applique avec une indication de format explicite :
FROM read_csv('/data/advertising/*.tsv', delim=' ', header=true)
Ce n'est pas une fonctionnalité de commodité. C'est un modèle mental différent pour travailler avec des données basées sur des fichiers : le système de fichiers devient la base de données. Le schéma est inféré, pas déclaré. Les requêtes se composent entre les limites des fichiers sans aucune étape de prétraitement. Pour l'analyse ad hoc, où la question change plus vite qu'un pipeline ETL ne peut être mis à jour, cette architecture est le défaut correct.
Caractéristiques de performance
Sur notre ensemble de données de référence – 4 200 fichiers, environ 2,8 Go non compressés – une agrégation complète des revenus groupée par marketplace, ASIN et mois se termine en 4,1 secondes sur un laptop standard (Apple M2, 16 Go de RAM). La requête PostgreSQL équivalente, sur des données importées et indexées, se termine en 2,8 secondes. Mais cette comparaison exclut les quarante minutes d'importation initiale, les migrations de schéma requises chaque fois qu'Amazon change un nom de colonne, et le coût continu de maintenance ETL. Sur le coût opérationnel total, DuckDB gagne décisivement pour cette charge de travail.
Si les performances des requêtes deviennent un goulot d'étranglement – typiquement à l'échelle multi-téraoctet – DuckDB lit Parquet nativement, et la conversion des fichiers CSV existants en Parquet est une opération unique :
COPY (FROM read_csv_auto('/data/**/*.csv'))
TO '/data/consolidated.parquet'
(FORMAT PARQUET);
Les requêtes ultérieures contre le fichier Parquet s'exécutent 8 à 12 fois plus vite qu'avec les CSV originaux. Parquet stocke des statistiques de colonnes – valeurs minimales et maximales par groupe de lignes – que DuckDB utilise pour sauter des sections entières de données sans les lire. Un filtre sur marketplace = 'DE' sur un fichier Parquet trié peut lire moins de dix pour cent des données sur disque. Ce pushdown de prédicats n'est pas disponible avec des fichiers CSV plats.
Construire un tableau de bord autonome avec Chart.js
La sortie des requêtes DuckDB est des données. La question pratique est qu'en faire. Pour le reporting interne des opérations Amazon de petite à moyenne taille, un fichier HTML autonome alimenté par Chart.js est souvent plus utile qu'un tableau de bord hébergé – pas de serveur à faire tourner, pas d'identifiants à gérer, pas d'instance Superset ou Metabase à maintenir.
Le pipeline fonctionne en trois étapes. D'abord, DuckDB exporte les résultats de requêtes en JSON :
COPY (
SELECT
strftime(date_trunc('week', "Date"), '%Y-%m-%d') AS week,
SUM("Units Ordered") AS units,
SUM("Ordered Product Sales") AS revenue
FROM read_csv_auto('/data/**/*.csv')
GROUP BY 1 ORDER BY 1
) TO 'weekly.json' (FORMAT JSON, ARRAY true);
Ensuite, un script Python lit ces fichiers JSON et intègre les données directement dans un template HTML référençant Chart.js via CDN. Enfin, le fichier HTML s'ouvre dans un navigateur sans serveur web requis.
<\!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Seller Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<canvas id="revenue"></canvas>
<script>
const rows = /* JSON_DATA_HERE */;
new Chart(document.getElementById('revenue'), {
type: 'line',
data: {
labels: rows.map(r => r.week),
datasets: [{ label: 'Revenue', data: rows.map(r => r.revenue), tension: 0.3 }]
}
});
</script>
</body>
</html>
Le résultat est un fichier autonome qui peut être partagé par e-mail, placé sur un bucket S3 privé, ou ouvert directement depuis un répertoire local. Pour les équipes opérationnelles qui ont besoin d'un reporting hebdomadaire sans la surcharge d'une infrastructure de tableau de bord en direct, cette approche est pragmatique et maintenable. Le tableau de bord se régénère en exécutant un script shell : DuckDB interroge les CSV, Python construit le HTML, terminé. Pas d'infrastructure, pas de coûts récurrents, pas de surface de maintenance.
Quand DuckDB bat PostgreSQL
DuckDB n'est pas un remplacement de PostgreSQL. La comparaison n'a de sens que lorsque la charge de travail est véritablement analytique – grands scans, agrégations, regroupements – et que les données sont principalement en lecture plutôt qu'en écriture. PostgreSQL gagne décisivement sur les écritures concurrentes, l'intégrité référentielle, le contrôle d'accès au niveau des lignes, et les exigences opérationnelles complètes d'une application de production. C'est le bon choix pour un système multi-utilisateurs où les enregistrements sont insérés, mis à jour et interrogés par le code applicatif.
DuckDB gagne quand :
- Les données existent déjà sous forme de fichiers sur disque, sans étape d'importation prévue
- Le schéma n'est pas entièrement connu à l'avance, ou change fréquemment
- Les requêtes sont ad hoc et les patterns d'accès ne peuvent pas être prédits à l'avance
- La surcharge opérationnelle d'un serveur de base de données n'est pas justifiée par la longévité ou l'échelle du projet
Les données Amazon Seller Central satisfont précisément ces quatre critères. Le schéma change à chaque version de Seller Central. Les fichiers existent déjà localement après l'export. Les questions métier changent d'une semaine à l'autre selon ce qui est optimisé. Et l'alternative – un pipeline ETL PostgreSQL maintenu – représente des semaines de temps d'ingénierie pour un problème que DuckDB résout en une après-midi.
La règle pratique : si vous atteigneriez normalement Excel ou un notebook Jupyter pour analyser ces données, optez plutôt pour DuckDB. Le SQL est plus expressif, les performances sont de plusieurs ordres de grandeur meilleures pour tout ce qui dépasse quelques milliers de lignes, et l'architecture basée sur des fichiers signifie que vos données restent là où elles sont déjà.
Insights connexes
- tva-fetch | How Complete Data Ownership Transforms Amazon Selling Operations
- Building Production-Ready Data Infrastructure for Amazon Sellers: Introducing tva-fetch
- Traefik Reverse Proxy: The Complete Self-Hosting Guide for HTTPS and SSL Automation
- Self-Hosting Windmill on Ubuntu: Complete Docker Setup Tutorial with PostgreSQL Troubleshooting