Row-based vs columnar: due modi di disporre i dati

La scelta del formato file è una decisione architetturale centrale in un data lake. Il discrimine principale è come i dati vengono fisicamente disposti su disco.

  • I formati row-based (es. CSV, JSON, Avro) memorizzano tutti i campi di una riga in modo contiguo. Sono ottimali per l’ingestion, per la scrittura di record completi e per gli append streaming, dove ogni evento arriva come riga intera. Avro in particolare è il formato di riferimento per Event Hubs / Kafka e per la schema evolution row-oriented.
  • I formati columnar (es. Parquet, ORC) memorizzano tutti i valori di una stessa colonna in modo contiguo. Sono ottimali per analytics e aggregazioni, perché una query tipicamente legge poche colonne su molte righe.

La regola d’esame: scritture frequenti di righe intere → row-based; query analitiche che leggono un sottoinsieme di colonne → columnar.

Parquet in profondità

Parquet è il formato columnar de facto nell’ecosistema Spark/Synapse/Fabric. Tre proprietà lo rendono efficiente:

  • Compressione: raggruppando valori omogenei nella stessa colonna, la compressione (Snappy di default, oppure Gzip/Zstd) è molto più efficace rispetto ai formati testuali. Snappy privilegia la velocità; Gzip un rapporto di compressione superiore a costo di più CPU.
  • Column pruning: se la query seleziona solo 3 colonne su 50, l’engine legge soltanto quei column chunk, saltando fisicamente il resto. Questo riduce drasticamente l’I/O.
  • Predicate pushdown: Parquet mantiene statistiche (min/max, conteggi) a livello di row group. Con un filtro WHERE data > '2026-01-01', l’engine può scartare interi row group senza leggerli, grazie ai metadati.

Column pruning e predicate pushdown sono i motivi per cui, a parità di dati, una query su Parquet costa meno di una su CSV: meno byte letti significa meno DWU/costo in Synapse e query più veloci in Spark.

Delta Lake: Parquet + transaction log

Delta Lake non è un formato concorrente di Parquet: è un livello transazionale costruito sopra Parquet. I dati restano file .parquet; ciò che aggiunge Delta è il transaction log (la cartella _delta_log/ con file JSON e checkpoint) che registra ogni operazione.

Questo abilita capacità che Parquet puro non ha:

  • Transazioni ACID su storage a oggetti (ADLS Gen2), quindi scritture concorrenti sicure.
  • UPDATE, DELETE e MERGE (upsert), essenziali per SCD, deduplica e requisiti GDPR (cancellazione mirata).
  • Time travel: interrogare una versione precedente della tabella (VERSION AS OF / TIMESTAMP AS OF).
  • Schema enforcement ed evolution controllata.

Quando Parquet puro e quando Delta

  • Parquet puro: layer di sola lettura, dati immutabili scritti una volta (write-once, es. archivio storico o output batch che non cambia), massima portabilità cross-engine.
  • Delta Lake: quando servono update/merge, letture consistenti durante scritture concorrenti, audit/rollback o un’architettura lakehouse (Medallion Bronze/Silver/Gold). In Microsoft Fabric, Delta è il formato nativo del OneLake.

Lo “small files problem”

Sia Parquet sia Delta soffrono quando lo streaming o micro-batch frequenti generano moltissimi file di piccole dimensioni. Ogni file comporta overhead di apertura e metadati: migliaia di file da pochi KB degradano gravemente le performance di lettura.

La soluzione è la compattazione, che riscrive molti file piccoli in pochi file grandi (idealmente 128 MB–1 GB):

  • In Delta: OPTIMIZE (con Z-Ordering opzionale per co-locare i valori più filtrati), e auto compaction/optimizeWrite.
  • In Spark su Parquet puro: repartition/coalesce in scrittura.
OPTIMIZE tabella_vendite ZORDER BY (data, id_cliente)

Trappole tipiche d’esame

  • Scenario: ingestion di eventi in streaming da Event Hubs, schema che evolve → risposta: formato row-based Avro in ingestion, non Parquet.
  • Scenario: query analitiche che aggregano poche colonne su miliardi di righe minimizzando l’I/O → risposta: Parquet (column pruning + predicate pushdown), non CSV/JSON.
  • Scenario: serve eseguire MERGE/upsert, cancellazioni GDPR o time travel sul data lake → risposta: Delta Lake; Parquet puro non supporta UPDATE/DELETE transazionali.
  • Scenario: dopo mesi di micro-batch, le letture Delta sono lentissime → risposta: small files problem, eseguire OPTIMIZE (compattazione), non aumentare il cluster.
  • Scenario: dati read-only da condividere con più engine esterni senza necessità transazionali → risposta: Parquet puro, più portabile del transaction log Delta.