Étape III : Exporter les données

ImportantExport parquet vs fichier .duckdb

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")
Astuce

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)
")
Note

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.

Astuce

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

Retour au sommet