Formats et stockage

30 questions en accès libre

Parquet, Delta Lake, CSV, colonnes contre lignes, partitionnement et petits fichiers : ce qu’on demande sur la couche de stockage d’un lac de données.

Niveau

Cliquez sur une question pour dérouler la réponse attendue.

  1. 01Pourquoi un format colonnes plutôt que lignes dans un lac ?Juniorcolonnesparquetstockage

    Parce que le lac sert surtout des lectures analytiques : on filtre et on agrège quelques colonnes sur beaucoup de lignes. Un format colonnes (Parquet, ORC) pose chaque colonne dans son propre flux, donc le moteur ne télécharge et ne décompresse que ce qu’il projette. Un format lignes (Avro, JSON, CSV) force à lire l’enregistrement entier pour extraire trois champs.

    C’est un argument d’entrée-sortie, pas de confort. Sur un objet de 800 Mo à 200 colonnes, une requête qui n’en touche que quatre peut lire quelques dizaines de Mo au lieu du fichier entier. Le facteur se retrouve sur la facture du stockage objet et sur le temps d’attente, quel que soit le moteur — Spark, Trino, DuckDB ou Athena.

    Le colonnes gagne aussi sur la compression : des valeurs d’un même type, souvent répétées, se compressent ensemble. Et il porte des statistiques par bloc (min, max, nulls) qui permettent de sauter des plages sans les ouvrir.

    Ce que l’intervieweur vérifie

    Que vous ne récitez pas « Parquet c’est mieux ». Vous savez quand le colonnes est le mauvais choix. Un flux qui relit toujours la ligne complète — CDC, file d’événements, reprise de streaming — n’a aucun bénéfice à projeter. Là, un format lignes (Avro) est plus naturel.

    La phrase qui clôt : le lac stocke pour être relu sélectivement ; le format suit ce contrat.

  2. 02Qu’est-ce qu’un row group Parquet et pourquoi ça compte ?Intermédiaireparquetrow-groupstockage

    Un row group est une tranche horizontale du fichier Parquet : un paquet de lignes — souvent 64 Mo à 1 Go non compressés — dans lequel chaque colonne est stockée à part, avec son propre mini-pied (min, max, nombre de nulls, encodage). Le fichier n’est pas une seule colonne géante : c’est une suite de ces tranches.

    Ça compte pour trois raisons concrètes.

    1. Unité de saut. Le predicate pushdown décide d’ouvrir ou d’ignorer un row group entier. Trop petits, les statistiques ne filtrent plus rien. Trop gros, on décompresse un pavé pour trois lignes utiles.
    2. Unité de mémoire. Le lecteur matérialise souvent un row group à la fois. Un groupe trop large fait gonfler le tas ; un groupe minuscule multiplie les allers-retours vers l’objet.
    3. Unité de parallélisme. Un fichier se découpe au row group. Un seul groupe énorme = un seul lecteur, même si le cluster a des cœurs libres.

    Ce que l’intervieweur vérifie

    Que vous ne confondez pas row group, page et fichier. La page (souvent 1 Mo) est le grain de compression et de dictionnaire à l’intérieur d’une colonne. Le fichier est l’objet S3. Le row group est le compromis entre les deux.

    Le chiffre à avoir en tête : viser des fichiers de 128 Mo à 1 Go avec des row groups assez larges pour que les stats servent, assez étroits pour rester parallélisables. Un Parquet de 20 ko n’a, en pratique, qu’un row group inutile.

  3. 03Projection pushdown et predicate pushdown : quelle différence ?Intermédiaireparquetpushdownperformance

    Deux mécanismes, deux économies, souvent confondus.

    La projection (column pruning) dit : « je n’ai besoin que de ces colonnes ». Le lecteur n’ouvre que les flux concernés dans chaque row group. C’est mécanique, et ça marche dès que le format est colonnes : une requête sur date et montant dans une table à 80 champs ne lit que deux colonnes.

    Le prédicat (predicate pushdown) dit : « je n’ai besoin que des lignes qui passent ce filtre ». Le lecteur consulte les statistiques du row group (min, max, nulls). Si date y va de janvier à mars et que le filtre demande date >= 2026-07-01, le groupe entier est sauté — sans décompresser. Si la plage chevauche, le groupe est lu, puis filtré en mémoire.

    Ce que l’intervieweur vérifie

    Que vous savez que le prédicat n’est pas une garantie. Des dates mélangées dans chaque fichier — un historique réécrit sans clustering — rendent min et max trop larges : plus aucun groupe n’est sautable. La projection, elle, continue de marcher.

    La relance classique : « et un LIKE '%foo%' ? » Le min/max ne sert à rien sur un motif au milieu d’une chaîne. Le moteur lira la colonne, éventuellement toute, même en Parquet.

    Formule à retenir : la projection économise des colonnes, le prédicat économise des blocs — à condition que les données soient rangées.

  4. 04À quoi servent l’encodage dictionnaire et le RLE dans Parquet ?Juniorparquetcompressionencodage

    À réduire le volume avant même le codec (Snappy, Zstd). Ce ne sont pas des algorithmes de compression généraux : ce sont des encodages de colonne, qui exploitent la répétition.

    Le dictionnaire remplace chaque valeur par un petit entier. Une colonne pays à 40 modalités distinctes dans un row group devient une table de 40 chaînes plus un flux d’indices. Sur une colonne à faible cardinalité, le gain est énorme. Sur un identifiant unique par ligne, le dictionnaire grossit autant que les données : Parquet le désactive au-delà d’un seuil (souvent quand le dictionnaire dépasse une page).

    Le RLE (run-length encoding) compacte les suites identiques : « France, 12 000 fois ». Il est très efficace après un tri ou un clustering, et presque inutile si les valeurs sont mélangées.

    Les deux se combinent souvent : dictionnaire, puis RLE sur les indices. C’est pour ça qu’une colonne catégorielle bien groupée pèse dix fois moins qu’un JSON équivalent.

    Ce que l’intervieweur vérifie

    Que vous reliez encodage et disposition. Un OPTIMIZE ZORDER BY pays n’accélère pas seulement le skip : il allonge les runs, donc le RLE. À l’inverse, des petits fichiers n’ont pas assez de valeurs pour qu’un dictionnaire soit rentable.

    Ne dites pas « Parquet compressé donc plus petit » : dites encodage de colonne, puis codec, et citez un cas où ça échoue (haute cardinalité, valeurs uniques).

  5. 05Parquet ou ORC : comment choisir ?Intermédiaireparquetorcformats

    Les deux sont colonnes, avec statistiques, encodages et compression. En entretien, le choix n’est pas « lequel est plus rapide », c’est quel écosystème vous devez servir.

    Parquet est le format d’échange du lac moderne : Spark, Trino, DuckDB, pandas, Athena, BigQuery, Snowflake (lecture externe), Flink. Un fichier Parquet écrit aujourd’hui reste lisible demain par un moteur que vous n’avez pas encore choisi. C’est l’argument qui pèse le plus.

    ORC reste très fort dans le monde Hive / Tez / Impala historique : index plus riches, indexes de bloom plus anciens, parfois une meilleure tenue sur des types Hive complexes. Si tout le parc lit via Hive et que personne n’emporte les fichiers ailleurs, ORC n’est pas une erreur.

    Trois critères concrets pour trancher :

    1. Portabilité. Plusieurs moteurs, ou un moteur futur inconnu : Parquet.
    2. Outil déjà en place. Une plateforme Hortonworks / Hive ancienne déjà en ORC : ne convertissez pas pour le plaisir.
    3. Tables transactionnelles. Delta et Iceberg posent du Parquet (Iceberg sait aussi ORC/Avro). Choisir ORC « nu » aujourd’hui, c’est souvent se fermer ces couches.

    Ce que l’intervieweur vérifie

    Que vous ne partez pas en benchmark de blog. Le piège est de comparer un ORC Hive 1.2 à un Parquet Spark 3.5 : vous mesurez la pile, pas le format.

    Réponse saine : Parquet par défaut, ORC seulement si le parc le dicte.

  6. 06Quand Avro est-il plus adapté que Parquet ?Intermédiaireavroparquetformats

    Quand vous relisez la ligne entière, souvent, et que le contrat qui compte est le schéma évolutif du producteur, pas la projection analytique.

    Avro est un format lignes, avec le schéma dans le fichier (ou via un schema registry). Écrire un événement, le relire tel quel, le republier : le coût est prévisible. Ajouter un champ optionnel, retirer un champ avec une règle de compatibilité (BACKWARD, FORWARD) : c’est le quotidien de Kafka, du CDC, des files d’ingestion.

    Parquet est le contraire : excellent pour scanner trois colonnes sur un an, médiocre comme format de buffer entre deux services. Un producteur qui émet des micro-lots Parquet crée des petits fichiers, paie un pied de fichier lourd, et n’offre aucun bénéfice de colonnes si le consommateur désérialise tout.

    Les cas où Avro gagne, à citer :

    • Journal d’événements et topics Kafka (souvent Avro + Schema Registry).
    • Zone brute d’un lac, avant le premier modelage : on archive le message tel quel.
    • Échange entre services où le schéma est le contrat, et où on ne fait pas d’agrégats.

    Ce que l’intervieweur vérifie

    Que vous ne dites pas « Avro c’est vieux ». Vous distinguez couche d’échange / de log et couche de stockage analytique. Le motif sain : Avro (ou JSONL) à l’arrivée, conversion une fois vers Parquet ou une table Iceberg/Delta, puis plus jamais de relecture du brut pour du reporting.

    Le contre-exemple à avoir : une table de faits de 400 colonnes relue par des analystes n’a rien à faire en Avro.

  7. 07Pourquoi JSON ou JSONL n’est pas un format de lac ?Juniorjsonformatsstockage

    Parce que JSON décrit un document, pas une table scannable. Chaque ligne (ou chaque objet) répète les noms de champs, ignore les types stables, et se lit de gauche à droite. Aucune projection, aucun prédicat sur statistiques, aucune compression colonnes. Vous payez le volume du texte et le parse de chaque enregistrement, à chaque requête.

    JSONL (un objet par ligne) est un peu moins pire que le JSON tableau unique : au moins le fichier est découpable. Ce n’est toujours pas un format de lac. C’est un format d’échange ou de journal — API, dumps d’application, zone brute.

    Les ennuis concrets qui sortent en entretien :

    • Schéma mou. Un champ absent ici, tableau là, chaîne demain : les moteurs infèrent n’importe quoi.
    • Types inventés. Un identifiant trop grand devient un flottant ; une date est une chaîne locale.
    • Coût de lecture. Relire 200 Go de JSONL pour un dashboard quotidien est une décision, pas une fatalité.

    Ce que l’intervieweur vérifie

    Que vous ne diabolisez pas le JSON : il est légitime à la frontière. La règle : on l’accepte une fois, on le valide contre un contrat (Avro, JSON Schema), on le matérialise en colonnes. Garder du JSONL comme table de faits « parce que c’est souple » est exactement ce qui rend un lac illisible six mois plus tard.

  8. 08Quels pièges du CSV restent à citer en entretien ?Juniorcsvschemaformats

    Le CSV n’a pas de schéma. Tout le reste en découle. En entretien, on ne vous demande plus « pourquoi Parquet » — c’est déjà ailleurs. On vérifie que vous avez déjà cassé un chargement CSV.

    Les pièges qui reviennent :

    1. Les types. Rien dans le fichier ne dit que 0012 est une chaîne. Un lecteur trop zélé en fait un entier et perd les zéros. Un N/A dans une colonne d’âges bascule tout en texte, et "9" > "18" devient vrai.
    2. Le séparateur. Point-virgule en France, virgule aux États-Unis, tabulation ailleurs. Un export Excel avec virgule décimale et point-virgule de champs casse un parseur « virgule par défaut ».
    3. L’encodage. Latin-1 côté applicatif, UTF-8 côté lac, BOM au début du premier fichier : des noms qui « marchent » jusqu’à la première cédille, puis des jointures qui ne joignent plus.
    4. Guillemets et retours à la ligne dans un champ. Un CSV mal échappé n’est plus aligné : le schéma glisse d’une colonne, silencieusement.
    5. Dates et locales. 03/04/2026 est le 3 avril ou le 4 mars selon l’émetteur.

    Ce que l’intervieweur vérifie

    Que votre réflexe n’est pas « j’infère le schéma ». C’est : contrat explicite (types, séparateur, encodage, nulls), rejet des lignes hors contrat, conversion une fois vers un format colonnes. Le CSV reste un format d’échange, pas une table.

  9. 09Où vit le schéma : dans le fichier, dans le catalog, ou les deux ?Intermédiaireschemacatalogparquet

    Les deux, avec des rôles distincts : le fichier dit ce qu’il contient vraiment, le catalog dit comment on l’appelle et ce qu’on a le droit d’y écrire.

    Lire la réponse détaillée
  10. 10Évolution de schéma : qu’est-ce qui casse une lecture ?Intermédiaireschemaevolutionparquet

    Pas « une colonne en plus ». Ajouter un champ nullable est l’évolution la plus sûre : les vieux fichiers n’ont pas la colonne, le lecteur pose des nulls. Ce qui casse, ce sont les changements non additifs.

    Les cas à citer, dans l’ordre où on les voit :

    1. Changement de type. INT vers STRING, TIMESTAMP vers DATE, DECIMAL(10,2) vers DOUBLE. Selon le moteur : erreur franche, ou conversion silencieuse qui arrondit les montants.
    2. Renommage. Pour un lecteur Parquet nu, client_id et id_client sont deux colonnes. Les anciennes valeurs deviennent nulles, les nouvelles aussi sur l’historique. Iceberg sait suivre un column id ; Parquet nu, non.
    3. Champ devenu obligatoire. Les fichiers anciens, sans la colonne, sont rejetés.
    4. Élargissement interdit. Passer un LONG dans une colonne cataloguée INT, ou une struct à un champ de plus lu par un écrivain vieux qui réécrit tout le type.
    5. Colonnes qui « disparaissent » du catalog alors que les fichiers les portent encore : selon le mode, elles sont ignorées — ou elles font échouer une lecture schema evolution = strict.

    Ce que l’intervieweur vérifie

    Que vous parlez de politique (Delta mergeSchema, Iceberg schema.update, compatibilité Avro), pas de chance. La relance : « comment vous ajoutez une colonne en production ? » Réponse attendue : job de migration versionné, écriture validée contre le catalog, lecture pinée sur une version le temps du bascule — pas un refresh en priant.

  11. 11Partitionnement Hive-style : comment choisir la colonne ?Intermédiairepartitionnementhivestockage

    On partitionne sur ce que presque toutes les lectures filtrent, à une cardinalité raisonnable, et qui sert aussi à expirer les données — rarement sur un identifiant.

    Lire la réponse détaillée
  12. 12Pourquoi partitionner sur un identifiant est une erreur ?Juniorpartitionnementcardinalitepetits-fichiers

    Parce qu’une partition n’est pas un index : c’est un dossier d’objets. Un user_id à dix millions de valeurs, c’est dix millions de préfixes. Chaque écriture pose un (ou plusieurs) fichiers minuscules dans un dossier presque vide. Vous n’avez plus une table : vous avez un listing S3.

    Trois factures, toutes payées avant le calcul :

    • Métadonnées. Le metastore ou le journal de table doit connaître chaque feuille. Iceberg/Delta tiennent mieux que Hive, mais un million de fichiers reste un million d’entrées à planifier.
    • Petits fichiers. Une partition qui reçoit 3 ko par micro-lot ne compressera jamais, n’aura pas de statistiques utiles, et coûtera un GET pour rien.
    • Élagage inutile. Personne ne fait WHERE user_id IN (8 millions d’id). On filtre un jour, un pays, un type d’événement. L’identifiant sert une jointure ou un point lookup — ce n’est pas le rôle d’un dossier Hive.

    Ce que l’intervieweur vérifie

    Que vous proposez autre chose que « alors on ne range pas ». Pour un accès par id : table de faits partitionnée par date, plus clustering sur l’id, ou un magasin clé-valeur à côté. Pour un WHERE user_id = ? fréquent et pointu, un lac colonnes n’est peut-être pas le bon système.

    La phrase nette : haute cardinalité = clustering ou index, pas partition.

  13. 13Clustering, Z-order et data skipping : qu’est-ce que ça change ?Seniorz-orderclusteringdata-skipping

    Ça range les valeurs proches dans les mêmes fichiers, donc les statistiques min-max redeviennent discriminantes et le moteur saute des blocs — sans exploser le nombre de dossiers.

    Lire la réponse détaillée
  14. 14Petits fichiers : quelles causes côté stockage et quels remèdes ?Intermédiairepetits-fichierscompactionstockage

    Trop d’écrivains, trop de partitions, trop de micro-lots : le lac se retrouve avec des millions d’objets. On compacte, on vise 128 Mo à 1 Go, et on arrête de découper plus fin que le volume.

    Lire la réponse détaillée
  15. 15Pourquoi des fichiers trop gros sont aussi un problème ?Intermédiairefichiersparquetstockage

    Parce que l’objet devient l’unité de parallèle et de réécriture. Un Parquet de 80 Go, même bien colonnes, se découpe au row group : trop peu de groupes, ou des groupes énormes, et une poignée de lecteurs portent tout le scan. Un nœud lent, un retry, et vous relisez des dizaines de Go.

    Pire : une mise à jour locale. En copy-on-write (Delta, Iceberg par défaut souvent), un MERGE qui touche 0,1 % des lignes réécrit le fichier entier. Un objet de 20 Go pour corriger 200 clés, c’est la facture qu’on découvre en production. En merge-on-read, le fichier reste, mais les delete files s’empilent jusqu’à une compaction qui, elle, paiera la réécriture.

    Les autres ennuis : un row group trop large tient mal en mémoire ; un objet qui dépasse les seuils de certaines couches (limites de split, timeouts de GET) échoue de façon opaque ; le restore d’un snapshot devient un monstre.

    Ce que l’intervieweur vérifie

    Que « plus gros = mieux » n’est pas votre règle. La cible usuelle reste 128 Mo à 1 Go compressés, assez pour amortir le footer et le listing, assez petite pour réécrire et paralléliser. Au-delà, on découpe (rewrite, bin-pack inverse), on n’admire pas le fichier unique.

    Cas limite acceptable : une table append-only, lue rarement, jamais mergée — un très gros objet dérange moins. Dès qu’il y a upsert ou time travel fin, la taille redevient un levier opérationnel.

  16. 16Comment le journal Delta Lake rend-il une table ACID ?Intermédiairedelta-lakeacidjournal

    Les données restent du Parquet ; le dossier delta log enchaîne des commits versionnés. Un lecteur ne voit qu’un snapshot fermé, une écriture concurrente se résout par conflit de version, pas par dossier à moitié rempli.

    Lire la réponse détaillée
  17. 17À quoi sert le time travel Delta, et que coûte-t-il ?Intermédiairedelta-laketime-travelstockage

    Il sert à relire un snapshot : VERSION AS OF ou TIMESTAMP AS OF. Trois usages qui passent en entretien : auditer ce qu’un job a vu hier ; rejouer un calcul après un mauvais chargement sans restaurer tout le bucket ; comparer deux versions (un EXCEPT entre v41 et v42) pour comprendre un MERGE.

    Ce n’est pas une machine à remonter le temps illimitée. Chaque version retenue empêche d’effacer les fichiers que cette version référence encore. Le coût est donc du stockage (anciens Parquet + log) et, parfois, de la complexité : un lecteur piné sur une vieille version voit un schéma ancien.

    La durée utile dépend de la rétention (delta.deletedFileRetentionDuration, souvent 7 jours par défaut sur beaucoup de plateformes) et de VACUUM. Au-delà, la version n’est plus matériellement là.

    Ce que l’intervieweur vérifie

    Que vous ne vendez pas le time travel comme un sauvegarde réglementaire. Sept jours de snapshots ≠ politique de backup, ≠ PRA hors région. Pour un audit long, on copie un snapshot (table clone, export) hors de la fenêtre de VACUUM.

    La relance : « ça ralentit les lectures courantes ? » Non, le courant lit le dernier checkpoint. Ça gonfle la facture objet et allonge VACUUM. Un MERGE toutes les minutes pendant un mois, sans compaction ni expiration, laisse une forêt de tombstones et d’anciens fichiers.

  18. 18VACUUM et rétention : quel est le piège avec le time travel ?Seniordelta-lakevacuumtime-travel

    VACUUM supprime les fichiers d’objets que plus aucune version dans la fenêtre de rétention ne référence. Après ça, VERSION AS OF trop ancien échoue, ou — pire selon l’outil — renvoie un état incomplet si quelqu’un a contourné le protocole. Le piège : on active le time travel dans les démos, puis un cron VACUUM à 24 h pour « faire le ménage », et l’équipe finance ne peut plus expliquer le chiffre de mardi.

    Deuxième piège, inverse : ne jamais vacuum. Les MERGE et OPTIMIZE laissent les anciens Parquet. Le bucket double tous les trimestres, les listings ralentissent, et personne ne relie ça au journal.

    La règle opérationnelle : rétention ≥ le plus long besoin de relecture (rejeu d’un job quotidien : 3–7 jours ; enquête fraude : beaucoup plus, donc clone ou backup, pas 90 jours de VACUUM retardé sur la table chaude). Et on ne vacuum pas en dessous du délai où un lecteur long (un streaming ouvert, un notebook oublié) tient encore un snapshot.

    Ce que l’intervieweur vérifie

    Que vous citez le seuil de sécurité historique de Delta (souvent 7 jours) et que vous savez pourquoi VACUUM … RETAIN 0 HOURS est une arme : ça casse les lecteurs concurrents et le time travel d’un coup. Sur Iceberg, l’équivalent est l’expiration de snapshots + delete orphan files : même tension, autres noms.

    Phrase attendue : time travel et VACUUM sont le même levier, pas deux fonctionnalités indépendantes.

  19. 19MERGE ou upsert dans un lac : quand l’utiliser, à quel prix ?Seniormergeupsertdelta-lake

    Quand une clé métier doit rester unique face à des arrivées tardives ou des corrections. Le prix est une réécriture de fichiers, pas une mise à jour de ligne : on s’en sert par lots, pas comme un UPDATE OLTP.

    Lire la réponse détaillée
  20. 20Iceberg, Delta Lake ou Hudi : quels critères de choix ?Senioricebergdelta-lakehudi

    On choisit d’abord l’écosystème de moteurs et le catalog, ensuite le type d’écriture (append, upsert massif, CDC). Le format de fichiers en dessous est presque toujours du Parquet.

    Lire la réponse détaillée
  21. 21Pourquoi un catalog est-il nécessaire, au-delà des fichiers ?Intermédiairecataloggluemetastore

    Le fichier dit comment lire un objet. Le catalog dit quelle table on interroge, où elle vit, qui y a droit, et quels fichiers en font partie — surtout dès que plusieurs moteurs partagent le lac.

    Lire la réponse détaillée
  22. 22Snappy, Zstd ou Gzip : quel compromis pour un lac ?Juniorcompressioncodecsparquet

    Un codec après l’encodage de colonnes. Le compromis est toujours le même : ratio contre CPU contre découpabilité.

    Snappy (et l’équivalent LZ4) : très rapide à compresser et décompresser, ratio moyen, splittable dans Parquet (on décompresse page par page). C’est le défaut historique de beaucoup de lacs : on privilégie le temps de scan.

    Zstd : souvent le meilleur équilibre aujourd’hui — meilleur ratio que Snappy, décompression encore vive, niveaux réglables. De plus en plus le choix par défaut quand la plateforme le propose.

    Gzip : meilleur ratio (surtout en niveau élevé), CPU cher, et un fichier gzip « nu » (CSV.gz, JSON.gz) n’est en général pas découpable : un seul lecteur pour tout l’objet. En page Parquet, Gzip reste splittable au grain de la page, mais reste plus lent. On le réserve à de l’archive froide rarement relue.

    Ce que l’intervieweur vérifie

    Que vous séparez codec dans Parquet et objet .gz. Le second est le piège classique d’ingestion. Et que vous ne changez pas de codec « pour gagner 8 % » sans mesurer le scan : un Zstd un peu plus petit mais plus long à décoder peut perdre sur un cluster déjà CPU-bound.

    Réponse saine : Zstd ou Snappy pour les tables chaudes, Gzip (ou glacé) pour l’archive, jamais de CSV.gz comme table de faits.

  23. 23À quoi servent les statistiques de fichiers dans un lac ?Intermédiairestatistiquesdata-skippingparquet

    À ne pas ouvrir les objets inutiles. Chaque fichier (et chaque row group) publie, pour les colonnes intéressantes, un min, un max, un compte de nulls, parfois un bloom filter ou des histogrammes. Le planificateur, avant les GET de données, compare ces bornes au WHERE. C’est le data skipping : la même idée que le predicate pushdown, remontée au manifeste de table (Delta, Iceberg) pour ne même pas considérer le fichier.

    Sans stats, ou avec des stats trop larges (valeurs mélangées), le moteur retombe sur un scan. D’où l’intérêt du clustering : resserrer les bornes. D’où aussi le coût des petits fichiers : des milliers de pieds à lire, chacun avec des stats médiocres.

    Iceberg pose ces stats dans les manifests ; Delta dans le log et les data skipping indexes / footers. Le lecteur SQL n’a pas à ouvrir 50 000 Parquet pour savoir lesquels touchent dt = 2026-09-13 si dt est aussi une partition — et s’il ne l’est pas, les stats sont le plan B.

    Ce que l’intervieweur vérifie

    Que vous savez quand elles mentent. Une colonne de type string mal parsée, un timestamp en plusieurs fuseaux, un float de montant : les bornes existent et ne servent à rien. Ou pire : stats absentes sur une colonne ajoutée après coup, jamais backfill.

    Relance : « ça suffit sans partition ? » Sur une petite table, oui. Sur un pétaoctet, les stats dans les manifests évitent le listing aveugle, mais une partition (ou un transform Iceberg) reste le premier couteau.

  24. 24Append, overwrite et dynamic overwrite : quelles différences ?Intermédiaireecriturepartitionsdelta-lake

    Trois contrats d’écriture, trois façons de perdre des données si on se trompe.

    Append. On ajoute des fichiers (et un commit). L’historique déjà publié reste. C’est le défaut sain pour des faits immuables. Le risque : doublons si on rejoue le même lot sans déduplication ni MERGE.

    Overwrite (table entière). Le nouveau snapshot remplace tous les fichiers. Utile pour une dimension recalculée de zéro, ou un datamart quotidien. Le risque : un job qui n’écrit que janvier efface février à décembre. En Parquet nu sans journal, un overwrite mal fait laisse un dossier à moitié vidé, visible tout de suite.

    Dynamic overwrite (overwrite des partitions présentes dans le lot). On réécrit dt=2026-09-13 sans toucher aux autres jours. C’est le mode des rejeux : « je recalcule la journée, pas le lac ». Le risque : une colonne de partition mal calculée (un null, un mauvais fuseau) crée une partition poubelle et/ou écrase la mauvaise feuille.

    Ce que l’intervieweur vérifie

    Que vous liez le mode au grain de rejeu. Relancer un lot horaire en overwrite global est une erreur de débutant. Relancer en append sans idempotence aussi. La phrase nette : append si l’événement est unique, overwrite dynamique si la partition est le grain de vérité, overwrite total seulement si la table entière est le résultat.

  25. 25Comment un lac gère-t-il les données qui arrivent en retard ?Intermédiairelate-datapartitionsmerge

    D’abord on distingue date d’événement et date d’ingestion. Une ligne du 10 arrive le 14 : si vous n’avez écrit que dans dt=2026-09-14 (ingestion), les requêtes « journée du 10 » sont fausses. Si vous écrivez dans dt=2026-09-10, vous devez rouvrir une partition fermée.

    Les stratégies, à citer sans en faire un cours :

    1. Fenêtre de grâce + overwrite dynamique de la partition événement. Simple, coûteux si le retard est long (réécriture de tout le jour).
    2. Append + vue « dernière version » (événement immuable + corrections en plus). Pas de réécriture ; les lecteurs filtrent.
    3. MERGE sur clé dans la partition (ou la table) concernée. Plus juste pour un état courant ; plus cher.
    4. Table des retards à part, compactée vers les faits une fois par jour. Isole le chaos du flux principal.

    Le watermark de streaming n’efface pas le problème métier : il dit seulement ce que le job refuse de réouvrir. Au-delà, c’est un process (rejeu, job de rattrapage), pas un paramètre.

    Ce que l’intervieweur vérifie

    Que vous ne répondez pas « on partitionne sur l’ingestion, donc pas de souci ». C’est un souci déplacé vers tous les dashboards. Et que vous chiffrez la fenêtre : 2 h, 2 jours, 2 semaines changent le layout et le budget de réécriture.

  26. 26Que doit-on savoir du chiffrement et du cycle de vie des objets ?Seniorchiffrementlifecyclesecurite

    Deux couches que le format de table ne remplace pas.

    Chiffrement. Au repos, presque toujours par le object store (SSE-S3, SSE-KMS, clés gérées). KMS donne rotation, audit, et la possibilité de révoquer un accès sans tout réécrire. Le chiffrement côté client (le job chiffre avant le PUT) existe ; il casse souvent le listing, les stats, et les services de compaction qui ne voient plus du Parquet. En transit : TLS, évident, à vérifier sur les endpoints privés.

    Une table Delta/Iceberg chiffrée fichier par fichier avec des clés différentes, sans le support de la plateforme, rend OPTIMIZE et les lecteurs tiers… intéressants. On aligne une politique (bucket + KMS + grants catalog).

    Cycle de vie. Transitions (Standard → IA → Glacier) et expirations. Le piège : un lifecycle qui efface des objets encore référencés par un snapshot, ou qui glace des fichiers que VACUUM n’a pas encore le droit de considérer morts. Inversement, garder Intelligent-Tiering sur une table chaude compactée toutes les heures coûte des retrievals. On couple rétention de table (snapshots, VACUUM) et règles bucket : même durée, mêmes préfixes, exception pour _delta_log / metadata qu’on n’envoie pas au Glacier à la légère.

    Ce que l’intervieweur vérifie

    Que vous parlez préfixe et snapshots, pas seulement « on a activé le chiffrement ». Un lac « sécurisé » dont le lifecycle détruit le log est un incident. Un lac chiffré dont tout le monde a s3:* sur le bucket est un théâtre.

  27. 27Quel format pour le streaming, quel format pour le batch ?Intermédiairestreamingbatchformats

    Ce n’est pas le même contrat de fichier.

    Le streaming produit souvent : petits lots, schéma contraint par un registry, besoin de reprendre à un offset. Avro (ou Protobuf) sur une file, puis écriture en table (Iceberg/Delta) avec roll de fichiers, voilà le motif sain. Écrire du Parquet à chaque micro-lot de 200 ko sans compaction, c’est fabriquer le lac illisible. JSONL en topic « pour aller vite » se paie au parse et au schéma mou.

    Le batch (rejeu quotidien, backfill, datamart) vise des gros objets colonnes, stats utiles, éventuellement overwrite dynamique d’une partition. Parquet / ORC dans une table transactionnelle. Relire le topic Avro de six mois pour un dashboard est un aveu : la couche batch n’existe pas.

    Les deux se rencontrent dans la table. Le stream commite des snapshots ; le batch lit le dernier (ou un pin). Ce n’est pas « Parquet versus Kafka » : Kafka n’est pas un lac. C’est file d’échange + table de stockage.

    Ce que l’intervieweur vérifie

    Que vous refusez « on met du Parquet partout » autant que « on garde du JSONL parce que c’est le stream ». Et que vous nommez le compactage comme partie du chemin streaming, pas comme un luxe batch du dimanche.

  28. 28Tables larges ou tables étroites : quel impact sur le stockage ?Juniormodeleparquetcolonnes

    En colonnes, une table large n’est pas une table lignes qui a grossi. Ajouter 80 colonnes rarement lues coûte surtout du schéma et un peu de footer, pas 80 fois le scan — si les lecteurs projettent. C’est pour ça qu’un lac tolère des faits très larges (une ligne d’événement avec des attributs) mieux qu’un OLTP.

    La facture revient autrement :

    • Écriture et MERGE. Une table à 400 champs, même si on n’en merge que trois, réécrit souvent tout le fichier (copy-on-write). Large + upsert = cher.
    • Petites colonnes très denses vs colonnes clairsemées. Une colonne à 99 % nulle se compresse bien ; 400 colonnes semi-vides alourdissent tout de même métadonnées et planning.
    • Évolution. Une table fourre-tout accumule les champs morts ; le catalog devient illisible, pas le disque.

    L’étroite (étoile : faits minces + dimensions) simplifie les MERGE de dimensions et les droits. Elle coûte des jointures. En lac, une jointure large tous les matins peut valoir plus cher que trois colonnes de trop dans le fait — à mesurer.

    Ce que l’intervieweur vérifie

    Que vous ne récitez pas « 3NF partout ». Vous parlez projection, réécriture, consommation. Large pour des faits append-only très lus par colonnes ; étroit quand l’upsert et la gouvernance de colonnes dominent.

  29. 29Comment diagnostiquer qu’un lac est devenu illisible ?Seniordiagnosticpetits-fichiersschema

    On mesure d’abord le planning et le listing, pas le CPU : explosion d’objets, schémas qui divergent, partitions vides, et des lectures qui n’osent plus passer par le catalog.

    Lire la réponse détaillée
  30. 30Quelle règle d’or un intervieweur attend-il entre échange et stockage ?Juniorformatsstockageechange

    On n’entrepose pas dans le format avec lequel on s’échange.

    L’échange (API, export métier, topic, pièce jointe) privilégie ce que l’autre système sait lire : CSV, JSON, Avro, Excel. C’est ponctuel, souvent verbeux, souvent sans stats. Le stockage d’un lac privilégie ce qu’on va relire cent fois : colonnes, pied de fichier, commits, catalog. On convertit à la frontière, une fois, avec un schéma explicite, puis les jobs internes ne revoient plus le CSV.

    La phrase inverse est aussi vraie : on ne sort pas un datamart en posant un préfixe Parquet sur un partenaire qui attend un CSV horodaté. On exporte depuis la table, on n’invite pas le partenaire dans le _delta_log.

    Ce que l’intervieweur vérifie

    Que vous avez une ligne : brut d’échange → validation → table colonnes (Iceberg/Delta/Parquet tenu) → export éventuel. Pas une zone raw qui est devenue le reporting. C’est la même idée que « le CSV n’est pas un format de stockage », généralisée à JSON, Excel, et aux dumps applicatifs.

    Si vous ne dites qu’une phrase dans tout l’entretien formats : échange à la porte, colonnes et catalog à l’intérieur.