Parquet, le format de fichier colonnaire

Résumé

Parquet stocke un tableau de données colonne par colonne dans un fichier. Le fichier est découpé en row groups (row groups), chacun contenant un bloc par colonne (column chunk). Un footer à la fin du fichier décrit le schéma et l’emplacement de chaque bloc. Un lecteur lit d’abord ce footer, puis ne va chercher que les colonnes (et, avec les statistiques, les row groups) dont la requête a besoin. C’est pourquoi Parquet est le format de fichier par défaut des lacs et des lakehouses.

Prérequis

OLTP vs OLAP et stockage en colonnes pour la différence entre lignes et colonnes.

Structure d’un fichier

La spécification officielle décrit cette disposition :1

PAR1 (4 octets, marqueur)
  Row group 1 : colonne 1, colonne 2, … colonne N
  Row group 2 : colonne 1, colonne 2, … colonne N
  …
  Row group M : colonne 1, colonne 2, … colonne N
Métadonnées du fichier (footer)
Longueur des métadonnées (4 octets)
PAR1 (4 octets, marqueur)
flowchart LR
    F["Fichier Parquet"] --> RG1["Row group 1"]
    F --> RG2["Row group 2"]
    F --> FT["Footer : schéma, positions des blocs, statistiques"]
    RG1 --> C1["Bloc colonne A"]
    RG1 --> C2["Bloc colonne B"]
    C1 --> P1["Pages : unité de compression et d'encodage"]

Points tirés de la spécification :

  • Les métadonnées sont écrites après les données, pour permettre d’écrire le fichier en un seul passage.
  • Un lecteur commence par le footer, y trouve la position de chaque column chunk, puis lit les blocs qui l’intéressent.
  • Les métadonnées sont séparées des données par conception. Cela permet de répartir des colonnes sur plusieurs fichiers, ou de faire référencer plusieurs fichiers Parquet par un seul fichier de métadonnées.

Pourquoi c’est rapide à lire

Deux économies se cumulent.

1. Lire moins de colonnes (projection). Une requête SELECT SUM(montant) ne lit que les blocs de la colonne montant. Les autres ne sont pas touchés.

2. Sauter des row groups (predicate pushdown). Le footer peut contenir, pour chaque column chunk, des statistiques comme la valeur minimale et maximale. Si le filtre de la requête est incompatible avec ces bornes, le row group entier est ignoré.

Les statistiques sont définies dans la définition Thrift du format : une structure Statistics (valeurs minimale et maximale) par column chunk, et des index de pages (ColumnIndex, OffsetIndex) qui permettent de sauter des pages à l’intérieur d’un row group.

Exemple : un fichier de 4 row groups, trié par date.

Groupemin(date)max(date)Lu pour WHERE date = '2026-10-15' ?
12026-10-012026-10-07Non
22026-10-082026-10-14Non
32026-10-152026-10-21Oui
42026-10-222026-10-28Non

Un seul groupe est lu sur quatre. Si les mêmes données étaient dans un ordre quelconque, chaque groupe contiendrait des dates de tout le mois : les bornes se chevaucheraient et les quatre groupes seraient lus.

L'ordre d'écriture compte

Les statistiques ne servent que si elles sont resserrées. Écrire les données triées sur la colonne filtrée le plus souvent (souvent la date) est un des leviers les plus efficaces. C’est le même principe que le clustering des entrepôts.

Compression et encodage

Parce qu’un column chunk contient des valeurs du même type et souvent proches, il se compresse bien. Des encodages comme le dictionnaire ou l’encodage par plages (run-length) réduisent encore la taille : une colonne « pays » qui ne prend que 30 valeurs distinctes se stocke en numéros de dictionnaire. L’unité de compression et d’encodage est la page, à l’intérieur d’un column chunk.

Comparaison avec d’autres formats

FormatDispositionSchémaUsage typique
CSVTexte, ligne par ligneAucun, tout est du texteÉchange simple, petits volumes
JSONTexte, document par documentImplicite, varie d’une ligne à l’autreÉvénements bruts, API
AvroBinaire, ligne par ligneEmbarqué dans le fichierIngestion, flux de messages
ParquetBinaire, colonne par colonneEmbarqué dans le fichierAnalytique, lacs, lakehouses

Ce que Parquet ne fait pas

  • Pas de transactions ni de modification en place. Un fichier Parquet est immuable. Modifier une ligne revient à réécrire le fichier. C’est ce que les formats de table (Iceberg, Delta) gèrent par-dessus : Data lake vs lakehouse.
  • Un schéma par fichier. Chaque fichier porte le sien ; rien ne garantit que deux fichiers du même dossier soient cohérents. Voir le cas du renommage de colonne dans Data lake vs lakehouse.
  • Petits fichiers : un coût. Beaucoup de petits fichiers multiplient les footers à lire et les ouvertures. La parade est la compaction : Maintenance d’un lakehouse.

Inspecter un fichier

DuckDB expose les métadonnées d’un fichier Parquet :

SELECT row_group_id, path_in_schema, stats_min_value, stats_max_value
FROM parquet_metadata('events.parquet');

Cela montre, pour chaque row group et chaque colonne, les bornes utilisées pour sauter des blocs. Les noms de colonnes de cette fonction peuvent varier selon la version de DuckDB : vérifier avec DESCRIBE SELECT * FROM parquet_metadata('events.parquet').

Taille des row groups

La documentation officielle recommande de grands row groups, de 512 Mo à 1 Go, pour que la lecture soit efficace.2 Certains écrivains utilisent par défaut des groupes plus petits (de l’ordre de 128 Mo) : la taille se règle selon le moteur et le fichier. Voir aussi la taille cible des fichiers dans Maintenance d’un lakehouse.

Notes liées

Notes de bas de page

  1. Apache Parquet, File Format et Metadata, documentation officielle consultée le 24 octobre 2026. ↩

  2. Apache Parquet, Configurations, documentation officielle. ↩