Il problema degli small files

In un Lakehouse di Microsoft Fabric le tabelle sono in formato Delta Lake, ossia file Parquet più un transaction log (_delta_log). Ogni scrittura in streaming, ogni MERGE, ogni micro-batch o ingestion incrementale produce nuovi file. Con il tempo la tabella accumula centinaia o migliaia di file piccoli (spesso pochi KB o MB): è il classico small files problem.

L’impatto è sulle letture. Ogni file comporta overhead di apertura, lettura dei metadati e task Spark dedicato. Molti file piccoli significano molti task minuscoli, scheduling inefficiente e I/O frammentato, quindi query lente sia dal motore Spark sia dall’endpoint SQL analytics e da Power BI in Direct Lake.

OPTIMIZE: bin-compaction e V-Order

Il comando OPTIMIZE risolve il problema con la bin-compaction: riscrive molti file piccoli in un numero ridotto di file più grandi (target indicativo circa 1 GB), senza cambiare i dati logici.

OPTIMIZE tabella_vendite;

Sopra la compaction si innesta V-Order, ottimizzazione proprietaria di Fabric applicata in scrittura ai file Parquet (sorting, encoding e compressione mirati). V-Order rende i file più efficienti per i motori che leggono in colonnare — Direct Lake, VertiPaq, SQL — riducendo dimensioni e migliorando il data skipping. In Fabric la scrittura Spark applica V-Order secondo configurazione; puoi forzarlo in un OPTIMIZE ... VORDER o come proprietà di tabella.

Z-Order e data skipping

Per query molto selettive su una o più colonne puoi aggiungere Z-ORDER, che raggruppa fisicamente i dati per quelle colonne (multi-dimensional clustering), massimizzando lo skip dei file irrilevanti:

OPTIMIZE tabella_vendite ZORDER BY (data, id_cliente);

Scegli come chiavi Z-Order le colonne usate spesso nei filtri, non quelle di partizionamento.

VACUUM e la retention

OPTIMIZE riscrive i dati ma non cancella i vecchi file: restano referenziati dal log per garantire time travel e transazioni ACID. Ripulirli è compito di VACUUM, che rimuove i file non più referenziati dalla versione corrente e più vecchi della retention (default 7 giorni / 168 ore).

VACUUM tabella_vendite RETAIN 168 HOURS;

La retention è il punto delicato: definisce quanto indietro puoi fare time travel e rollback. VACUUM elimina i file necessari alle versioni oltre la finestra di retention. Abbassarla troppo riduce lo storage ma rompe la capacità di rollback e può far fallire lettori/scrittori concorrenti che stanno ancora usando quei file.

Table maintenance del Lakehouse

Fabric offre una Table maintenance integrata: dalla vista Lakehouse, tasto destro sulla tabella Delta → Maintenance. In un’unica operazione puoi:

  • eseguire OPTIMIZE (con o senza V-Order);
  • eseguire VACUUM con una retention scelta.

È l’approccio consigliato per la manutenzione ricorrente perché non richiede notebook custom; per pipeline automatizzate si schedula comunque OPTIMIZE/VACUUM via notebook o job.

Partizionamento e statistiche

  • Partizionamento: partiziona su colonne a bassa cardinalità e usate nei filtri (es. anno/mese). Il sovra-partizionamento su colonne ad alta cardinalità genera esso stesso small files, peggiorando le letture. Per tabelle piccole/medie spesso conviene non partizionare e affidarsi a V-Order + Z-Order.
  • Statistiche: Delta raccoglie automaticamente min/max/null count sulle prime 32 colonne e le usa per il data skipping. Colonne filtrate frequentemente vanno posizionate all’inizio dello schema (o si aumenta il numero di colonne su cui raccogliere statistiche) perché lo skipping sia efficace.

Trappole tipiche d’esame

  • Query lente su tabella con ingestion in streaming continua → il problema sono gli small files: esegui OPTIMIZE (bin-compaction), non aumentare la capacity.
  • Serve migliorare le letture Direct Lake / Power BI da Lakehouse → assicurati che V-Order sia attivo in scrittura o riapplicalo con OPTIMIZE ... VORDER, non basta partizionare.
  • VACUUM con RETAIN 0 HOURS o retention molto bassarompe il time travel e può far fallire query/scritture concorrenti; è la risposta sbagliata anche se “libera storage”. Bilancia costo storage e finestra di rollback (default 7 giorni).
  • Lo storage cresce anche dopo OPTIMIZE → normale: OPTIMIZE non elimina i vecchi file, serve VACUUM (rispettando la retention) per recuperare spazio.
  • Filtri selettivi su poche colonne restano lenti dopo OPTIMIZE → aggiungi Z-ORDER BY su quelle colonne per abilitare il data skipping; il partizionamento non è la scelta giusta per colonne ad alta cardinalità.