Étape III : Exporter les données
TOUJOURS privilégier un export dans un fichier parquet plutôt qu’une sauvegarde dans une base .duckdb. Parquet est un format ouvert, stable et lisible par tous les écosystèmes (Python, R, Spark, DuckDB…), alors qu’un .duckdb est un format interne lié à la version du moteur, sans garantie de compatibilité dans la durée. Il apporte en plus compression, partitionnement et lecture sélective des colonnes.
Une fois le résultat de l’étude prêt, on l’enregistre dans un fichier. DuckDB fait cela avec une seule instruction SQL : COPY ... TO .... Pas besoin d’un package supplémentaire (pas de arrow, pas de write.csv) : DuckDB écrit lui-même le fichier, au format demandé.
On exécute cette commande depuis R avec DBI::dbExecute().
Exporter une table stocké dans la base duckDB
DBI::dbExecute(con, "
COPY ma_table
TO 'resultat.parquet'
(FORMAT parquet)
")Le format est déduit de l’extension du fichier (.parquet, .csv) mais peut aussi être précisé explicitement avec FORMAT, comme ci-dessus.
Exporter un data.frame R
COPY ne fonctionne que sur une table ou une vue DuckDB, pas directement sur un data.frame R (par exemple un résultat de dplyr::collect()). Pour exporter un data.frame en SQL, on l’enregistre d’abord comme vue avec duckdb::duckdb_register() :
duckdb::duckdb_register(con, "resultat_vue", resultat)
DBI::dbExecute(con, "
COPY resultat_vue
TO 'resultat.parquet'
(FORMAT parquet)
")
duckdb::duckdb_unregister(con, "resultat_vue")duckdb_register() ne copie pas les données : il crée une vue qui pointe directement vers le data.frame R. C’est plus léger que DBI::dbWriteTable(), qui dupliquerait les données dans DuckDB avant de pouvoir les exporter. On peut retirer la vue une fois l’export terminé avec duckdb_unregister().
Exporter le résultat d’une requête
On peut exporter directement le résultat d’un SELECT, sans passer par une table intermédiaire — c’est le cas le plus fréquent pour une réponse à la demande, où l’on ne livre que le résultat final.
DBI::dbExecute(con, "
COPY (
SELECT region, AVG(valeur) AS valeur_moyenne
FROM ma_table
WHERE annee = 2024
GROUP BY region
)
TO 'resultat_regions_2024.parquet'
(FORMAT parquet)
")Exporter au format CSV
Utile quand le fichier est destiné à être ouvert dans Excel ou par une personne qui n’utilise pas R.
DBI::dbExecute(con, "
COPY (
SELECT region, AVG(valeur) AS valeur_moyenne
FROM ma_table
WHERE annee = 2024
GROUP BY region
)
TO 'resultat_regions_2024.csv'
(FORMAT csv, HEADER true, DELIMITER ';')
")Exporter directement sur S3
Si l’accès S3 a été configuré (voir étape I), on peut écrire directement vers un chemin s3://, sans passer par un fichier local :
DBI::dbExecute(con, "
COPY (
SELECT region, AVG(valeur) AS valeur_moyenne
FROM ma_table
WHERE annee = 2024
GROUP BY region
)
TO 's3://mon-bucket/mon-etude/resultat_regions_2024.parquet'
(FORMAT parquet)
")Découper l’export en plusieurs fichiers (optionnel)
Pour un gros résultat, on peut demander à DuckDB de créer un fichier par valeur d’une colonne (par exemple un fichier par région), avec PARTITION_BY. Le résultat est alors un dossier contenant plusieurs fichiers Parquet plutôt qu’un seul fichier.
DBI::dbExecute(con, "
COPY ma_table
TO 's3://mon-bucket/mon-etude/export_par_region'
(FORMAT parquet, PARTITION_BY (region))
")Concrètement, DuckDB crée un sous-dossier par valeur distincte de la colonne de partition, nommé colonne=valeur, contenant les lignes correspondantes :
export_par_region/
├── region=A/data_0.parquet
└── region=B/data_0.parquet
Ce découpage (format « Hive ») permet aussi, à la relecture, de ne charger que les partitions utiles si l’on filtre sur cette colonne — sans avoir à lire tout le dossier.
Si le dossier de destination existe déjà et contient des fichiers, DuckDB refuse d’écrire par défaut (pour éviter d’écraser un export existant par erreur). Pour relancer l’export et remplacer les fichiers, on ajoute l’option OVERWRITE_OR_IGNORE :
DBI::dbExecute(con, "
COPY ma_table
TO 's3://mon-bucket/mon-etude/export_par_region'
(FORMAT parquet, PARTITION_BY (region), OVERWRITE_OR_IGNORE)
")OVERWRITE_OR_IGNORE n’a d’effet que pour les exports en plusieurs fichiers (PARTITION_BY, comme ici, ou PER_THREAD_OUTPUT/FILE_SIZE_BYTES). Pour un export simple vers un seul fichier (sans ces options), DuckDB réécrit déjà le fichier existant par défaut, sans rien avoir à préciser.
Pour réduire la taille des fichiers Parquet exportés, on peut préciser une compression, par exemple COMPRESSION zstd (bon rapport taille/vitesse, activé par défaut sur les versions récentes de DuckDB).
Sources
- Instruction
COPY: duckdb.org/docs/current/sql/statements/copy - Export partitionné (Hive) : duckdb.org/docs/current/data/partitioning/partitioned_writes
- Client R (
duckdb_register(),duckdb_unregister()) : duckdb.org/docs/current/clients/r - Écriture de fichiers Parquet : duckdb.org/docs/current/data/parquet/overview
- Configuration S3 (pour l’export direct vers
s3://) : duckdb.org/docs/current/core_extensions/httpfs/s3api