DuckDB : le nouveau couteau suisse de l'analyse de données
Si vous faites de l'analyse de données, vous avez probablement ce workflow : 1. Extraire les données (CSV, Parquet, base SQL...) 2. Charger en Pandas 3. RAM qui explose 4. Attendre 10 minutes qu'un groupby se termine 5. Crash. Recommencer sur une machine plus grosse.
Et si je vous disais qu'il existe une solution qui :
- ⚡ Requête 100× plus rapide que Pandas
- 💾 Analyse 100 Go sur un laptop 16 Go de RAM
- 📁 Lit directement CSV/Parquet/JSON sans import
- 🔧 Zero configuration, zero serveur
- 🐍 S'intègre parfaitement avec Python/R/Node.js
- 🆓 Open source et gratuit
Cette solution, c'est DuckDB.
Décrit comme "SQLite pour l'analytique", DuckDB est en train de révolutionner la façon dont on analyse les données. Après 6 mois d'utilisation intensive, je peux dire une chose : c'est un game changer absolu.
Dans cet article, je partage :
- Pourquoi DuckDB explose en 2025
- Benchmarks réels vs Pandas, PostgreSQL, SQLite
- 10 use cases concrets avec code
- Les pièges à éviter
- Quand l'utiliser (ou pas)
$2
La définition en 30 secondes
DuckDB = SQLite mais optimisé pour l'analytique
| Caractéristique | SQLite | DuckDB |
| Use case | OLTP (transactions) | OLAP (analytics) |
| Stockage | Orienté ligne | Orienté colonne |
| Vitesse lecture | Correcte | Ultra-rapide |
| Vitesse écriture | Ultra-rapide | Correcte |
| Agrégations | Lent sur big data | Optimisé |
| Parallélisation | Non | Oui (multi-core) |
En pratique :
- SQLite : Applications CRUD, mobile apps, petites DB
- DuckDB : Analyse de données, data science, BI, ETL
L'architecture qui change tout

Stockage en colonnes (comme Parquet) :
# Orienté ligne (SQLite, PostgreSQL)
Row 1: [Alice, 25, France, 50000] Row 2: [Bob, 30, USA, 60000] Row 3: [Carol, 28, UK, 55000]
Orienté colonne (DuckDB, Parquet)
Avantage pour l'analytique :
-- Query: Salaire moyen par pays
SELECT country, AVG(salary) FROM employees GROUP BY country;
Résultat : 10-100× plus rapide sur requêtes analytiques.
Vectorisation SIMD :
DuckDB traite les données par "vecteurs" (batches) au lieu de ligne par ligne :
# Traitement traditionnel (ligne par ligne)
for row in table: result += row.salary * 1.1
DuckDB (vectorisé SIMD)
result = vector_multiply(salary_column, 1.1)
Gain : 5-20× plus rapide grâce aux instructions CPU modernes.
Les caractéristiques killer
1. In-process (pas de serveur)
import duckdb
C'est tout ! Pas de serveur, pas de config
Vs PostgreSQL :
- Installer PostgreSQL
- Configurer le serveur
- Gérer les connexions
- Gérer les permissions
- Monitorer les ressources
2. Requêtes SQL sur fichiers bruts
# Requête directe sur CSV (sans import!)
con.execute(""" SELECT country, COUNT(*) as count FROM 'sales_2024.csv' GROUP BY country ORDER BY count DESC """).df()
Parquet
con.execute("SELECT * FROM 'data.parquet' WHERE year = 2024").df()
JSON
con.execute("SELECT * FROM 'logs.json' LIMIT 10").df()
Plusieurs fichiers avec glob
con.execute("SELECT FROM 'sales_.csv'").df()
Même depuis S3/HTTP !
Zero ETL. Zero import. Requête directe.
3. Intégration Python transparente
import pandas as pd
import duckdb
df = pd.read_csv('data.csv')
Requête SQL sur DataFrame Pandas directement !
result = duckdb.query(""" SELECT category, SUM(revenue) as total FROM df WHERE year = 2024 GROUP BY category """).df()
Ou inversement : DuckDB → Pandas
4. Parallélisation automatique
# DuckDB utilise TOUS les cœurs CPU automatiquement
con.execute("SELECT * FROM huge_table GROUP BY category")
Pas de configuration nécessaire
5. Out-of-core processing
# Dataset 100 Go sur machine 16 Go RAM ? Pas de problème !
con.execute(""" SELECT country, AVG(revenue) FROM 'huge_dataset.parquet' GROUP BY country """).df()
DuckDB stream les données depuis le disque
$2
Setup des tests
Dataset : Logs e-commerce (identique à l'article Polars)
- 47,234,891 lignes
- 10.2 Go (CSV) / 2.8 Go (Parquet)
- 15 colonnes (mix types)
Config :
- MacBook Pro M3 Max (16 cœurs, 64 Go RAM)
- DuckDB 0.10.0
- Pandas 2.2.0
- PostgreSQL 16.2
- SQLite 3.45.0
Test #1 : Lecture d'un fichier Parquet 2.8 Go
import time
import pandas as pd import duckdb import sqlite3
Pandas
start = time.time() df = pd.read_parquet('logs.parquet') pandas_time = time.time() - start
DuckDB
start = time.time() result = duckdb.execute("SELECT * FROM 'logs.parquet'").df() duckdb_time = time.time() - start
SQLite (après import)
... import préalable nécessaire ...
Résultats :
| Outil | Temps | RAM pic | Speedup |
| Pandas | 8.7s | 12.4 Go | 1× |
| DuckDB | 1.2s | 3.1 Go | 7.3× plus rapide ✅ |
| PostgreSQL | 4.5s | 8.2 Go | 1.9× |
| SQLite | 45.3s | 15.1 Go | 0.19× ❌ |
DuckDB domine sur lecture de fichiers analytiques.
Test #2 : Agrégation simple (SUM + GROUP BY)
SELECT endpoint, SUM(response_time_ms) as total_time
Résultats :
| Outil | Temps | Speedup |
| Pandas | 4.8s | 1× |
| DuckDB | 0.18s | 26.7× plus rapide ✅ |
| PostgreSQL | 2.3s | 2.1× |
| SQLite | 28.4s | 0.17× ❌ |
DuckDB écrase tout grâce au stockage colonne + vectorisation.
Test #3 : JOIN complexe
SELECT
Résultats :
| Outil | Temps | Speedup |
| Pandas | 12.4s | 1× |
| DuckDB | 0.67s | 18.5× plus rapide ✅ |
| PostgreSQL | 3.8s | 3.3× |
| SQLite | 67.2s | 0.18× ❌ |
DuckDB : Hash join optimisé + parallélisé.
Test #4 : Window functions
SELECT
Résultats :
| Outil | Temps | Speedup |
| Pandas | 34.2s | 1× |
| DuckDB | 2.1s | 16.3× plus rapide ✅ |
| PostgreSQL | 18.7s | 1.8× |
| SQLite | 124.5s | 0.27× ❌ |
Test #5 : Requête sur CSV (sans import)
# DuckDB : requête directe
start = time.time() result = duckdb.execute("SELECT * FROM 'logs.csv' WHERE status_code >= 500").df() duckdb_time = time.time() - start
Temps: 3.4s
Pandas : import puis filter
start = time.time() df = pd.read_csv('logs.csv') result = df[df['status_code'] >= 500] pandas_time = time.time() - start
Temps: 127.8s
PostgreSQL : import obligatoire d'abord
DuckDB : 37.6× plus rapide car optimise la lecture (lit seulement les colonnes nécessaires).
Benchmark récapitulatif

| Opération | Pandas | DuckDB | PostgreSQL | SQLite | Gagnant |
| Read Parquet | 8.7s | 1.2s | 4.5s | 45.3s | 🥇 DuckDB |
| Agrégation | 4.8s | 0.18s | 2.3s | 28.4s | 🥇 DuckDB |
| JOIN | 12.4s | 0.67s | 3.8s | 67.2s | 🥇 DuckDB |
| Window func | 34.2s | 2.1s | 18.7s | 124.5s | 🥇 DuckDB |
| Query CSV | 127.8s | 3.4s | N/A | N/A | 🥇 DuckDB |
| MOYENNE | 37.6s | 1.5s | 7.3s | 66.4s | 🥇 DuckDB |
DuckDB est 25× plus rapide que Pandas en moyenne sur ces benchmarks.
$2
Use case #1 : Exploration de données ad-hoc
Problème : CSV de 5 Go, vous voulez juste voir les stats de base.
Solution DuckDB :
import duckdb
Pas besoin de charger en RAM !
con = duckdb.connect()
Stats descriptives
con.execute(""" SELECT COUNT(*) as total_rows, COUNT(DISTINCT user_id) as unique_users, MIN(timestamp) as first_event, MAX(timestamp) as last_event, AVG(response_time_ms) as avg_response, PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY response_time_ms) as p95 FROM 'large_file.csv' """).df()
Temps gagné : 95%
Use case #2 : ETL sans framework
Problème : Transformer des données CSV → Parquet avec filtres et agrégations.
Solution :
# ETL complet en 5 lignes
duckdb.execute(""" COPY ( SELECT DATE_TRUNC('day', timestamp) as date, country, endpoint, COUNT(*) as request_count, AVG(response_time_ms) as avg_response, SUM(CASE WHEN status_code >= 500 THEN 1 ELSE 0 END) as errors FROM 'raw_logs_*.csv' WHERE timestamp >= '2024-01-01' GROUP BY date, country, endpoint ) TO 'aggregated_data.parquet' (FORMAT PARQUET, COMPRESSION ZSTD) """)
Pas de Pandas, pas d'Airflow, pas de Spark
Résultat :
- 100 Go de CSV → 2 Go de Parquet
- Temps : 8 minutes
- Code : 5 lignes
Alternative Pandas :
- 50+ lignes de code
- 45 minutes
- Risques OOM
Use case #3 : Jointure entre fichiers CSV
Problème : Joindre sales.csv (10 Go) avec customers.csv (500 Mo).
# Sans import, sans merge Pandas qui explose la RAM
result = duckdb.execute(""" SELECT s.order_id, s.amount, c.customer_name, c.segment FROM 'sales.csv' s JOIN 'customers.csv' c ON s.customer_id = c.id WHERE s.order_date >= '2024-01-01' """).df()
Vs Pandas :
# Charger 10.5 Go en RAM
sales = pd.read_csv('sales.csv') # OOM probable customers = pd.read_csv('customers.csv')
Merge
result = sales.merge(customers, left_on='customer_id', right_on='id') result = result[result['order_date'] >= '2024-01-01']
Use case #4 : Analyse de logs applicatifs
Problème : Détecter anomalies dans 50 Go de logs JSON.
# DuckDB peut lire JSON nativement !
anomalies = duckdb.execute(""" SELECT DATE_TRUNC('hour', timestamp::TIMESTAMP) as hour, endpoint, COUNT(*) as request_count, AVG(response_time) as avg_response, PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY response_time) as p99 FROM 'logs/*.json' WHERE timestamp::TIMESTAMP >= CURRENT_DATE - INTERVAL '7 days' GROUP BY hour, endpoint HAVING request_count > 10000 OR p99 > 2000 ORDER BY hour DESC """).df()
Gain :
- Pas de preprocessing JSON
- Requête en 30-60s sur 50 Go
- RAM stable (< 4 Go)
Use case #5 : Time series analysis
# Analyse de série temporelle avec window functions
time_series = duckdb.execute(""" SELECT DATE_TRUNC('hour', timestamp::TIMESTAMP) as hour, AVG(cpu_usage) as avg_cpu,
-- Moving average 24h AVG(cpu_usage) OVER ( ORDER BY DATE_TRUNC('hour', timestamp::TIMESTAMP) ROWS BETWEEN 23 PRECEDING AND CURRENT ROW ) as moving_avg_24h,
-- Spike detection CASE WHEN cpu_usage > AVG(cpu_usage) OVER ( ORDER BY DATE_TRUNC('hour', timestamp::TIMESTAMP) ROWS BETWEEN 23 PRECEDING AND CURRENT ROW ) * 1.5 THEN TRUE ELSE FALSE END as is_spike
FROM 'metrics.parquet' WHERE timestamp::TIMESTAMP >= CURRENT_DATE - INTERVAL '30 days' ORDER BY hour """).df()
Ensuite visualiser avec Matplotlib/Plotly
Use case #6 : Data warehouse local
Problème : Besoin d'un data warehouse pour analytics, mais pas envie de setup Snowflake/BigQuery.
Solution : DuckDB comme DW local
# Créer un DW persistant
con = duckdb.connect('analytics.duckdb')
Importer depuis plusieurs sources
con.execute(""" CREATE TABLE sales AS SELECT * FROM 'raw_sales.csv' """)
con.execute(""" CREATE TABLE customers AS SELECT * FROM 'crm_export.parquet' """)
con.execute(""" CREATE TABLE products AS SELECT * FROM read_json_auto('products.json') """)
Index pour performance
con.execute("CREATE INDEX idx_sales_date ON sales(order_date)") con.execute("CREATE INDEX idx_customer_id ON customers(id)")
Requêtes BI
Use case réel :
- Startup 15 personnes
- Remplace Metabase + PostgreSQL
- DuckDB + Streamlit = BI complet
- Coût : $0 (vs $500/mois)
Use case #7 : Feature engineering pour ML
# Préparer features pour modèle ML
features = duckdb.execute(""" WITH user_activity AS ( SELECT user_id, COUNT(*) as num_sessions, SUM(duration) as total_time, AVG(duration) as avg_session_time, COUNT(DISTINCT DATE(timestamp)) as active_days, MAX(timestamp) as last_activity, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY duration) as median_duration FROM 'user_sessions.parquet' WHERE timestamp >= CURRENT_DATE - INTERVAL '90 days' GROUP BY user_id ), user_purchases AS ( SELECT user_id, COUNT(*) as num_purchases, SUM(amount) as total_spent, AVG(amount) as avg_order_value FROM 'purchases.parquet' WHERE purchase_date >= CURRENT_DATE - INTERVAL '90 days' GROUP BY user_id ) SELECT a.user_id, a.num_sessions, a.total_time, a.avg_session_time, a.active_days, EPOCH(CURRENT_TIMESTAMP - a.last_activity) / 86400 as days_since_last_activity, COALESCE(p.num_purchases, 0) as num_purchases, COALESCE(p.total_spent, 0) as total_spent, COALESCE(p.avg_order_value, 0) as avg_order_value, COALESCE(p.total_spent / NULLIF(a.num_sessions, 0), 0) as revenue_per_session FROM user_activity a LEFT JOIN user_purchases p ON a.user_id = p.user_id """).df()
Export pour scikit-learn
X = features.drop(['user_id'], axis=1).values
Avantage : SQL = lisible et maintenable vs code Pandas complexe.
Use case #8 : A/B test analysis
ab_test_results = duckdb.execute("""
WITH variant_metrics AS ( SELECT variant, COUNT(DISTINCT user_id) as users, COUNT(*) as events, SUM(CASE WHEN event_type = 'conversion' THEN 1 ELSE 0 END) as conversions, AVG(revenue) as avg_revenue FROM 'ab_test_events.parquet' WHERE experiment_id = 'checkout_redesign_v2' GROUP BY variant ) SELECT variant, users, conversions, ROUND(conversions::FLOAT / users * 100, 2) as conversion_rate, ROUND(avg_revenue, 2) as avg_revenue_per_user,
Use case #9 : Data quality checks
# Checks de qualité automatisés
quality_report = duckdb.execute(""" SELECT 'users' as table_name, COUNT(*) as total_rows, COUNT(DISTINCT id) as unique_ids, COUNT(*) - COUNT(DISTINCT id) as duplicate_count, COUNT(*) - COUNT(email) as null_emails, SUM(CASE WHEN email NOT LIKE '%@%.%' THEN 1 ELSE 0 END) as invalid_emails, SUM(CASE WHEN created_at > CURRENT_TIMESTAMP THEN 1 ELSE 0 END) as future_dates FROM 'users.csv'
UNION ALL
SELECT 'transactions' as table_name, COUNT(*) as total_rows, COUNT(DISTINCT transaction_id) as unique_ids, COUNT(*) - COUNT(DISTINCT transaction_id) as duplicate_count, COUNT(*) - COUNT(amount) as null_amounts, SUM(CASE WHEN amount < 0 THEN 1 ELSE 0 END) as negative_amounts, SUM(CASE WHEN transaction_date > CURRENT_DATE THEN 1 ELSE 0 END) as future_dates FROM 'transactions.parquet' """).df()
Alert si anomalies
Use case #10 : Incremental data processing
# Processing incrémental efficace
con = duckdb.connect('analytics.duckdb')
Créer table si n'existe pas
con.execute(""" CREATE TABLE IF NOT EXISTS daily_stats ( date DATE, metric VARCHAR, value DOUBLE, PRIMARY KEY (date, metric) ) """)
Identifier données déjà traitées
last_processed = con.execute(""" SELECT MAX(date) FROM daily_stats """).fetchone()[0]
Traiter seulement nouvelles données
con.execute(f""" INSERT INTO daily_stats SELECT DATE(timestamp) as date, 'revenue' as metric, SUM(amount) as value FROM 'transactions/*.parquet' WHERE DATE(timestamp) > '{last_processed}' GROUP BY DATE(timestamp)
UNION ALL
SELECT DATE(timestamp) as date, 'active_users' as metric, COUNT(DISTINCT user_id) as value FROM 'transactions/*.parquet' WHERE DATE(timestamp) > '{last_processed}' GROUP BY DATE(timestamp) """)
$2
DuckDB vs Pandas
Utiliser DuckDB si :
- Données > 1 Go
- Beaucoup de groupby/agrégations
- Joins complexes
- Workflow SQL préféré
- Performance critique
Utiliser Pandas si :
- Small data (< 500 Mo)
- Transformations complexes ligne par ligne
- Intégration ML (scikit-learn)
- Prototypage rapide
Best of both :
# Traitement lourd en DuckDB
aggregated = duckdb.execute(""" SELECT * FROM huge_dataset.parquet WHERE ... GROUP BY ... """).df()
Viz/analyse en Pandas
DuckDB vs PostgreSQL
Utiliser DuckDB si :
- Analytics (OLAP)
- Single-user ou embedded
- Fichiers (CSV/Parquet)
- Zero admin
- Local development
Utiliser PostgreSQL si :
- Production OLTP
- Multi-user concurrent
- Transactional integrity critique
- Besoin de permissions/sécurité
- Infrastructure existante
Cas hybride :
# Export PostgreSQL → DuckDB pour analytics
duckdb.execute(""" INSTALL postgres; LOAD postgres;
ATTACH 'host=localhost user=postgres password=xxx dbname=prod' AS pg (TYPE postgres);
CREATE TABLE local_copy AS SELECT * FROM pg.sales WHERE date >= '2024-01-01'; """)
Analytics en DuckDB (plus rapide)
DuckDB vs Spark
Utiliser DuckDB si :
- Single machine
- Données < 500 Go
- Development/analytics
- Simplicité
- Latence faible (secondes)
Utiliser Spark si :
- Cluster distribué
- Données > 1 To
- Production ETL à grande échelle
- Infrastructure Hadoop existante
- Batch processing (minutes/heures OK)
Benchmark (100 Go de données) :
| Métrique | DuckDB (1 machine 64 Go) | Spark (3 machines 64 Go) |
| Setup time | 0s | 15 min |
| Query time | 45s | 2m30s |
| Code complexity | SQL simple | PySpark verbose |
| Cost | $0 | $2-5/hour |
Conclusion : Pour < 500 Go, DuckDB est souvent plus rapide et simple que Spark.
DuckDB vs SQLite
Utiliser DuckDB si :
- Analytics/OLAP
- Agrégations lourdes
- Gros fichiers
- Performance critique
Utiliser SQLite si :
- OLTP (transactions)
- Embedded DB dans app
- Write-heavy workload
- Millions de petites transactions
Règle simple :
- Besoin de
INSERT/UPDATErapides → SQLite - Besoin de
SELECT/GROUP BYrapides → DuckDB
$2
Piège #1 : Pas optimisé pour OLTP
# ❌ MAUVAISE utilisation : write-heavy
for transaction in millions_of_transactions: con.execute(f"INSERT INTO sales VALUES ('{transaction.id}', ...)")
Très lent !
✅ BONNE utilisation : batch insert
con.execute(""" INSERT INTO sales SELECT * FROM 'transactions.csv' """)
Règle : DuckDB = batch analytics, pas single-row OLTP.
Piège #2 : Pas de server = pas de concurrent access
# ❌ Ne fonctionne PAS bien
Process 1
con1 = duckdb.connect('db.duckdb') con1.execute("INSERT INTO ...")
Process 2 (simultané)
DuckDB = single writer (comme SQLite).
Solution : Mode read-only pour lecteurs multiples
# Process lecteur
Piège #3 : Types de données implicites
# Attention aux types auto-détectés
result = duckdb.execute("SELECT * FROM 'data.csv'").df()
DuckDB infère les types, parfois mal
Solution : Spécifier les types
duckdb.execute("""
Piège #4 : Mémoire avec lazy evaluation
# DuckDB charge pas tout en RAM... sauf si vous forcez !
df = duckdb.execute("SELECT * FROM 'huge_file.parquet'").df()
⚠️ .df() matérialise TOUT en RAM
✅ Mieux : itérer par batches
Piège #5 : Extensions à installer
# Certaines fonctionnalités nécessitent extensions
duckdb.execute("INSTALL httpfs") # Pour lire S3/HTTP duckdb.execute("LOAD httpfs")
Extensions utiles :
httpfs: S3, HTTP, GCSparquet: Parquet avancé (auto-loaded)json: JSON avancépostgres: Connect à PostgreSQLspatial: GIS/géospatialexcel: Lire fichiers Excel
$2
Python
import duckdb
In-memory
con = duckdb.connect()
Persistent
con = duckdb.connect('mydb.duckdb')
Query
result = con.execute("SELECT * FROM ...").fetchall() df = con.execute("SELECT * FROM ...").df() # → Pandas
Query sur Pandas DataFrame
R
library(duckdb)
con <- dbConnect(duckdb::duckdb(), "mydb.duckdb")
Query
result <- dbGetQuery(con, "SELECT * FROM 'data.csv'")
Intégration dplyr
Node.js
const duckdb = require('duckdb');
const db = new duckdb.Database(':memory:');
CLI
# Installation
brew install duckdb # macOS apt install duckdb # Ubuntu
Utilisation
duckdb mydb.duckdb
Requête directe
duckdb -c "SELECT * FROM 'data.csv' LIMIT 10"
Pipeline
Jupyter notebooks
# Install extension Jupyter
%load_ext sql %config SqlMagic.autopandas = True
Magic command
$2
Extensions officielles
- httpfs : Lecture S3, GCS, HTTP
- postgres : FDW PostgreSQL
- mysql : Connect MySQL
- sqlite : Read SQLite databases
- spatial : PostGIS-like features
- icu : Internationalization
- tpch : TPC-H benchmark data
- fts : Full-text search
Outils de l'écosystème
Harlequin : TUI SQL client pour DuckDB
pip install harlequin
Evidence : BI tool basé sur DuckDB
Rill : Dashboards opérationnels avec DuckDB backend
Motherduck : DuckDB cloud (serverless analytics)
# DuckDB local ↔ Motherduck cloud
$2
Après 6 mois d'utilisation intensive, DuckDB a remplacé 80% de mes usages Pandas.
Ce que j'ai gagné
Performance :
- Requêtes 10-100× plus rapides
- RAM divisée par 3-5
- Fichiers de 50-100 Go manipulables sur laptop
Productivité :
- SQL = plus lisible que code Pandas complexe
- Zero setup (vs PostgreSQL, Spark)
- Requêtes directes sur fichiers (zero ETL)
Coûts :
- Pas de serveur à maintenir
- Pas d'infrastructure cloud nécessaire
- Open source, gratuit
Mes use cases quotidiens
1. Exploration de données : Ouvrir un CSV/Parquet et l'analyser en SQL 2. ETL léger : Transformer fichiers sans framework lourd 3. Analytics local : DW personnel pour dashboards 4. Feature engineering : Préparer données pour ML 5. Data quality : Checks automatisés
Quand je n'utilise PAS DuckDB
- OLTP : PostgreSQL reste king
- Production multi-user : PostgreSQL/MySQL
- Big data distribué : Spark (> 500 Go)
- Prototypage rapide : Pandas (< 100 Mo)
- ML pipelines : Pandas + scikit-learn
Ma recommandation 2025
Si vous faites de l'analyse de données :
- Apprenez DuckDB, c'est un game changer
- Commencez par remplacer vos scripts Pandas lents
- Utilisez-le comme DW local pour développement
- Découvrez les extensions (httpfs, spatial...)
DuckDB = le SQLite de l'analytique. Simple, rapide, efficace. Un outil qui va rester.
Vous utilisez déjà DuckDB ? Partagez vos use cases en commentaires ! 👇