Delta Lake vs Apache Iceberg 2026: Architettura Lakehouse e Domande per Colloqui

Confronto tra Delta Lake e Apache Iceberg per architetture Data Lakehouse. Modelli transazionali, evoluzione delle partizioni, compatibilità con i motori e domande frequenti nei colloqui per Data Engineer.

Confronto Architettura Delta Lake vs Apache Iceberg Lakehouse 2026

Delta Lake e Apache Iceberg rappresentano i due formati di tabella aperti dominanti che alimentano i moderni data lakehouse nel 2026. Entrambe le tecnologie risolvono lo stesso problema fondamentale – portare transazioni ACID, evoluzione dello schema e time travel allo storage a oggetti cloud – ma adottano approcci architetturali differenti che impattano significativamente i carichi di lavoro in produzione.

Confronto Rapido

Delta Lake eccelle negli ambienti Spark-nativi con stretta integrazione Databricks, mentre Iceberg offre compatibilità più ampia con i motori (Spark, Trino, Flink, Dremio) e partizionamento più flessibile attraverso le hidden partition e l'evoluzione delle partizioni.

Delta Lake vs Iceberg: Differenze Architetturali Fondamentali

Entrambi i formati memorizzano i dati come file Parquet su object storage, ma i loro livelli di metadati differiscono significativamente.

Delta Lake utilizza un transaction log (_delta_log/) contenente file JSON che registrano ogni modifica. Ogni commit crea un nuovo file JSON, e checkpoint periodici consolidano questi in Parquet per letture più veloci. La specifica del protocollo Delta Lake definisce funzionalità reader/writer versionate per la compatibilità in avanti.

Apache Iceberg mantiene una gerarchia di file di metadati: un file JSON di metadati che punta a liste di manifest, che a loro volta puntano a manifest contenenti statistiche a livello di file. Questo design abilita il predicate pushdown già in fase di pianificazione – il motore di query salta interi file prima di leggere qualsiasi dato.

| Funzionalità | Delta Lake | Apache Iceberg | |--------------|------------|----------------| | Transaction Log | JSON + checkpoint Parquet | Metadata JSON + file manifest | | Evoluzione Partizioni | Richiede riscrittura | In-place senza riscrittura | | Supporto Engine | Spark, Trino, Flink | Spark, Trino, Flink, Dremio, Athena | | Time Travel | Basato su versioni | Basato su snapshot con branch/tag | | Evoluzione Schema | Aggiunta/rinomina colonne | Aggiunta/rinomina/riordino/estensione colonne |

Hidden Partition: Il Vantaggio Chiave di Iceberg

Il partizionamento tradizionale stile Hive espone le colonne di partizione nelle query (WHERE year=2026 AND month=7), accoppiando il layout fisico alla sintassi SQL. Le hidden partition di Iceberg disaccoppiano queste preoccupazioni.

python
# iceberg_partition_example.py
from pyiceberg.catalog import load_catalog
from pyiceberg.schema import Schema
from pyiceberg.types import StringType, TimestampType, LongType, NestedField
from pyiceberg.partitioning import PartitionSpec, PartitionField
from pyiceberg.transforms import MonthTransform

# Definizione dello schema
schema = Schema(
    NestedField(1, "event_id", LongType(), required=True),
    NestedField(2, "event_time", TimestampType(), required=True),
    NestedField(3, "user_id", StringType(), required=True),
    NestedField(4, "event_type", StringType(), required=False),
)

# Hidden partition sul mese estratto da event_time
partition_spec = PartitionSpec(
    PartitionField(
        source_id=2,  # campo event_time
        field_id=1000,
        transform=MonthTransform(),
        name="event_month"
    )
)

catalog = load_catalog("glue", **{"type": "glue"})
catalog.create_table(
    identifier="analytics.events",
    schema=schema,
    partition_spec=partition_spec
)

Le query filtrano direttamente su event_time – il motore applica automaticamente il partition pruning senza esporre la colonna di partizione nella clausola WHERE. L'evoluzione delle partizioni permette alla tabella di passare da partizionamento mensile a giornaliero senza riscrivere i dati esistenti.

Transazioni ACID e Optimistic Concurrency in Delta Lake

Delta Lake implementa l'isolamento serializable utilizzando l'optimistic concurrency control. I writer verificano il transaction log prima del commit per rilevare conflitti.

python
# delta_concurrent_writes.py
from delta import DeltaTable
from pyspark.sql import SparkSession

spark = SparkSession.builder \
    .config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
    .config("spark.sql.catalog.spark_catalog", 
            "org.apache.spark.sql.delta.catalog.DeltaCatalog") \
    .getOrCreate()

# Operazione MERGE concorrente con risoluzione automatica dei conflitti
delta_table = DeltaTable.forPath(spark, "s3://bucket/events")

# Merge dei dati in ingresso con i dati esistenti
delta_table.alias("target").merge(
    source=incoming_df.alias("source"),
    condition="target.event_id = source.event_id"
).whenMatchedUpdateAll() \
 .whenNotMatchedInsertAll() \
 .execute()

# Il rilevamento dei conflitti avviene automaticamente durante il commit
# Le transazioni fallite vengono ritentate con lo snapshot aggiornato

Le regole di risoluzione dei conflitti di Delta Lake permettono append concorrenti mentre serializzano gli update in conflitto sulla stessa partizione.

Confronto tra Time Travel e Versionamento dei Dati

Entrambi i formati supportano il time travel, ma con semantiche diverse.

sql
-- Delta Lake: Query per numero di versione
SELECT * FROM events VERSION AS OF 42;

-- Delta Lake: Query per timestamp
SELECT * FROM events TIMESTAMP AS OF '2026-07-15 10:00:00';

-- Iceberg: Query per snapshot ID
SELECT * FROM analytics.events FOR SYSTEM_VERSION AS OF 8823749234;

-- Iceberg: Query per timestamp
SELECT * FROM analytics.events FOR SYSTEM_TIME AS OF TIMESTAMP '2026-07-15 10:00:00';

Iceberg 1.5+ aggiunge branching e tagging – è possibile creare branch nominati per sperimentazione isolata, quindi unire o scartare. Delta Lake raggiunge workflow simili attraverso shallow clone.

sql
-- Iceberg: Creare un branch per i test
ALTER TABLE analytics.events CREATE BRANCH experiment;

-- Scrivere nel branch senza influenzare main
INSERT INTO analytics.events.branch_experiment 
SELECT * FROM staging.events WHERE event_type = 'test';

-- Unire il branch a main
CALL system.fast_forward('analytics.events', 'main', 'experiment');

Pronto a superare i tuoi colloqui su Data Engineering?

Pratica con i nostri simulatori interattivi, flashcards e test tecnici.

Matrice di Compatibilità dei Query Engine

La compatibilità con i motori guida la selezione del formato per molte organizzazioni.

| Engine | Supporto Delta Lake | Supporto Iceberg | |--------|---------------------|-------------------| | Apache Spark | Nativo (Databricks, OSS) | Nativo | | Trino/Presto | Connector | Nativo | | Apache Flink | Connector | Nativo (1.16+) | | Dremio | Solo lettura | Nativo | | AWS Athena | Limitato | Nativo | | Snowflake | External tables | Nativo (Iceberg tables) | | BigQuery | External tables | BigLake Iceberg |

Per ambienti solo Spark, l'integrazione più stretta di Delta Lake offre migliori prestazioni. Le architetture multi-engine beneficiano della più ampia compatibilità di Iceberg – l'Iceberg REST Catalog fornisce un'API vendor-neutral per le operazioni di catalogo.

Tecniche di Ottimizzazione delle Prestazioni

Entrambi i formati richiedono operazioni di manutenzione per prestazioni di query ottimali.

python
# delta_optimize.py
from delta import DeltaTable

delta_table = DeltaTable.forPath(spark, "s3://bucket/events")

# Compattare file piccoli (bin-packing)
delta_table.optimize().executeCompaction()

# Z-order per predicati multi-colonna
delta_table.optimize().executeZOrderBy("user_id", "event_time")

# Rimuovere vecchie versioni (vacuum)
delta_table.vacuum(retentionHours=168)  # Mantenere 7 giorni
sql
-- Iceberg: Riscrivere i file di dati per la compattazione
CALL catalog.system.rewrite_data_files(
  table => 'analytics.events',
  strategy => 'binpack',
  options => map('target-file-size-bytes', '134217728')
);

-- Iceberg: Far scadere i vecchi snapshot
CALL catalog.system.expire_snapshots(
  table => 'analytics.events',
  older_than => TIMESTAMP '2026-07-01 00:00:00',
  retain_last => 10
);

Lo Z-ordering raggruppa dati correlati, migliorando l'efficacia del predicate pushdown. Entrambi i formati beneficiano della compattazione dei file quando si ingestiscono molti file piccoli da sorgenti streaming.

Domande Frequenti nei Colloqui sui Data Lakehouse

Queste domande vengono poste regolarmente nei colloqui di data engineering.

D: Quando scegliere Iceberg rispetto a Delta Lake?

Iceberg è più adatto quando: (1) più query engine accedono alle stesse tabelle (Spark, Trino, Flink), (2) gli schemi di partizione devono evolversi senza riscrittura dei dati, (3) l'organizzazione preferisce standard aperti vendor-neutral. Delta Lake eccelle nelle architetture centrate su Databricks o negli ambienti Spark puri dove Unity Catalog fornisce la governance.

D: Come raggiunge Iceberg l'evoluzione delle partizioni senza riscrittura dei dati?

Iceberg memorizza le specifiche delle partizioni come metadati. Quando la specifica cambia, i nuovi dati usano il nuovo partizionamento mentre i dati esistenti mantengono il loro layout originale. Il query planner legge tutte le specifiche di partizione e applica la logica di pruning corretta per ogni gruppo di file.

D: Spiegare il meccanismo di checkpoint di Delta Lake.

Delta Lake crea file di checkpoint ogni 10 commit per default. Un checkpoint consolida il transaction log in un singolo file Parquet per letture più veloci. Il file _last_checkpoint punta al checkpoint più recente, e i reader ricostruiscono lo stato leggendo il checkpoint più eventuali commit JSON successivi.

D: Cos'è copy-on-write vs merge-on-read?

Copy-on-write (COW) riscrive interi file sugli update – costo di scrittura maggiore ma letture più veloci. Merge-on-read (MOR) scrive i delta separatamente, unendo al momento della query – latenza di scrittura inferiore ma overhead in lettura. Iceberg supporta entrambi; Delta Lake usa principalmente COW con deletion vector per soft delete nelle versioni recenti.

Esercitarsi con questi pattern sulle domande per colloqui data engineering di SharpSkill per consolidare la comprensione prima dei colloqui.

Percorso di Migrazione: Conversione tra Formati

Le organizzazioni a volte devono migrare tra formati. Entrambi supportano utility di conversione.

python
# Convertire Delta in Iceberg usando Spark
spark.sql("""
    CALL catalog.system.snapshot(
        source_table => 'delta.`s3://bucket/delta_events`',
        table => 'analytics.events_iceberg'
    )
""")

# Convertire Iceberg in Delta
from delta.tables import DeltaTable

iceberg_df = spark.read.format("iceberg").load("catalog.analytics.events")
iceberg_df.write.format("delta").save("s3://bucket/delta_events")

Una migrazione completa richiede validazione accurata dei tipi di schema, semantica del partizionamento e compatibilità dei consumer downstream.

Conclusioni

  • Scegliere Delta Lake per workload Spark-nativi, ambienti Databricks e quando la governance di Unity Catalog soddisfa le esigenze organizzative
  • Scegliere Iceberg per architetture multi-engine, requisiti di evoluzione delle partizioni e deployment cloud-agnostici
  • Entrambi i formati offrono transazioni ACID, time travel ed evoluzione dello schema – la scelta giusta dipende dall'infrastruttura esistente e dalla diversità dei query engine
  • La preparazione ai colloqui dovrebbe coprire gli aspetti interni del transaction log, l'ottimizzazione del partition pruning e i tradeoff COW vs MOR
  • La compattazione dei file e l'expiration degli snapshot rimangono attività di manutenzione critiche indipendentemente dalla scelta del formato

Inizia a praticare!

Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.

Tag

#delta-lake
#apache-iceberg
#data-lakehouse
#data-engineering
#spark

Condividi

Articoli correlati