MERGE ou upsert dans un lac : quand l’utiliser, à quel prix ?

Questions d’entrevue Formats et stockage

Seniormergeupsertdelta-lake

La réponse courte

Un lac n’a pas de « ligne à mettre à jour ». Un MERGE compare une source (nouveaux événements, CDC, corrections) à la table, puis réécrit les fichiers touchés (copy-on-write) ou pose des delete vectors / delete files (merge-on-read) pour masquer les anciennes lignes. L’upsert est légitime quand le métier a une clé et que le réel arrive plusieurs fois : commande amendée, profil client, CDC d’une table source, RGPD (DELETE logique).

Il n’est pas légitime comme substitut d’une base opérationnelle. Si vous mergez une clé à la fois toutes les secondes, vous payez la planification, le listing des fichiers candidats, et souvent la réécriture d’un objet de plusieurs centaines de Mo. Le pattern sain : accumuler (file, table de staging), merger par vagues (toutes les 5–15 minutes, ou au-delà d’un volume), compacte ensuite.

Le prix, à savoir chiffrer en entretien

Copy-on-write. Simple à lire ensuite (que du Parquet propre). Coûteux à écrire : une clé dans un fichier de 800 Mo ≈ réécriture de 800 Mo. Plus les fichiers sont gros et mal clusterisés, plus un MERGE « léger » est cher. D’où clustering sur la clé de MERGE : moins de fichiers candidats.

Merge-on-read (Hudi MoR, Iceberg delete files, Delta deletion vectors). L’écriture est plus légère (petit fichier de tombstones). La lecture rejoue les suppressions. Sans compaction, les requêtes pourrissent. Vous déplacez la facture, vous ne l’annulez pas.

Contention. Deux MERGE sur la même table : conflits de version, retries. Une table « dimension client » mergée par cinq jobs indépendants est un anti-pattern. Un seul writer (ou une file unique) par table chaude.

Petits fichiers. Chaque MERGE qui crée de nouveaux objets sans bin-pack recrée le problème des petits fichiers. OPTIMIZE n’est pas optionnel sur une table d’upsert.

Ce que l’intervieweur vérifie

Que vous posez d’abord : peut-on rester append-only ? Un fait immuable (événement horodaté) n’a pas besoin de MERGE. On ajoute la correction comme une nouvelle ligne et on prend la dernière version en lecture (QUALIFY ROW_NUMBER()). C’est souvent plus simple, plus auditable, et ça stream mieux. Le MERGE devient intéressant quand les lecteurs ne doivent pas voir l’historique, ou quand le volume de corrections rend la vue « dernière ligne » trop chère.

La relance : « SCD type 2 ? » On attend que vous sépariez historique métier (nouvelles lignes versionnées) et upsert technique (une ligne courante). Les deux se stockent, mais ce n’est pas le même contrat.

Deuxième relance : « comment vous limitez les fichiers lus ? » Partition sur la date d’événement ou de mise à jour si le MERGE peut s’y restreindre (MERGE … ON … AND t.dt IN (dates de la source)), plus clustering sur la clé. Un MERGE qui scanne cinq ans pour 10 000 clés est un échec de layout, pas de SQL.

Le piège

Copier la syntaxe SQL d’une base et croire que le coût est le même. En OLTP, un index met à jour 1 kB. Dans le lac, vous touchez un objet. Si vous ne dites pas ce mot, l’intervieweur considère que vous n’avez jamais opéré une table Delta en production.

Toutes les questions Formats et stockage