Delta Lake vs Apache Iceberg w 2026: Architektura Lakehouse i Pytania Rekrutacyjne

Kompleksowe porównanie Delta Lake i Apache Iceberg - dwóch wiodących formatów tabel dla architektury data lakehouse. Poznaj kluczowe różnice, praktyczne przykłady kodu i typowe pytania z rozmów kwalifikacyjnych dla inżynierów danych.

Porównanie Delta Lake i Apache Iceberg dla architektury data lakehouse

Delta Lake oraz Apache Iceberg to dwa dominujące otwarte formaty tabel napędzające nowoczesne architektury data lakehouse w 2026 roku. Oba rozwiązują ten sam fundamentalny problem—wprowadzenie transakcji ACID, ewolucji schematu i podróży w czasie do chmurowego obiektowego przechowywania danych—jednak przyjmują różne podejścia architektoniczne, które mają znaczenie w środowiskach produkcyjnych.

Szybkie Porównanie

Delta Lake sprawdza się najlepiej w środowiskach natywnych dla Spark z ścisłą integracją Databricks, podczas gdy Iceberg oferuje szerszą kompatybilność z silnikami (Spark, Trino, Flink, Dremio) oraz bardziej elastyczne partycjonowanie dzięki ukrytym partycjom i ewolucji partycji.

Delta Lake vs Iceberg: Kluczowe Różnice Architektoniczne

Oba formaty przechowują dane jako pliki Parquet w obiektowym storage, jednak ich warstwy metadanych znacząco się różnią.

Delta Lake wykorzystuje dziennik transakcji (_delta_log/) zawierający pliki JSON rejestrujące każdą zmianę. Każdy commit tworzy nowy plik JSON, a okresowe checkpointy konsolidują je do formatu Parquet dla szybszego odczytu. Specyfikacja protokołu Delta Lake definiuje wersjonowane funkcje czytnika/pisarza dla kompatybilności wstecznej.

Apache Iceberg utrzymuje hierarchię plików metadanych: plik JSON metadanych wskazujący na listy manifestów, które wskazują na manifesty zawierające statystyki na poziomie plików. Ta konstrukcja umożliwia predicate pushdown na etapie planowania—silnik zapytań pomija całe pliki przed odczytaniem jakichkolwiek danych.

| Funkcja | Delta Lake | Apache Iceberg | |---------|------------|----------------| | Dziennik Transakcji | JSON + Parquet checkpointy | JSON metadanych + pliki manifestów | | Ewolucja Partycji | Wymaga przepisania | Na miejscu bez przepisania | | Wsparcie Silników | Spark, Trino, Flink | Spark, Trino, Flink, Dremio, Athena | | Podróż w Czasie | Oparta na wersjach | Oparta na snapshotach z branch/tag | | Ewolucja Schematu | Dodawanie/zmiana nazw kolumn | Dodawanie/zmiana nazw/zmiana kolejności/rozszerzanie kolumn |

Ukryte Partycje: Kluczowa Przewaga Iceberg

Tradycyjne partycjonowanie w stylu Hive eksponuje kolumny partycji w zapytaniach (WHERE year=2026 AND month=7), wiążąc układ fizyczny ze składnią SQL. Ukryte partycje Iceberg oddzielają te aspekty.

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

# Definicja schematu
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),
)

# Ukryta partycja na miesiącu wyodrębnionym z event_time
partition_spec = PartitionSpec(
    PartitionField(
        source_id=2,  # pole 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
)

Zapytania filtrują bezpośrednio po event_time—silnik automatycznie stosuje przycinanie partycji bez eksponowania kolumny partycji w klauzuli WHERE. Ewolucja partycji pozwala tabeli przejść z partycjonowania miesięcznego na dzienne bez przepisywania istniejących danych.

Transakcje ACID i Optymistyczna Współbieżność w Delta Lake

Delta Lake implementuje izolację serializowalną przy użyciu optymistycznej kontroli współbieżności. Pisarze sprawdzają dziennik transakcji przed zatwierdzeniem, aby wykryć konflikty.

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()

# Współbieżna operacja MERGE z automatycznym rozwiązywaniem konfliktów
delta_table = DeltaTable.forPath(spark, "s3://bucket/events")

# Scalanie przychodzącego batcha z istniejącymi danymi
delta_table.alias("target").merge(
    source=incoming_df.alias("source"),
    condition="target.event_id = source.event_id"
).whenMatchedUpdateAll() \
 .whenNotMatchedInsertAll() \
 .execute()

# Wykrywanie konfliktów następuje automatycznie podczas commitu
# Nieudane transakcje są ponawiane z zaktualizowanym snapshotem

Reguły rozwiązywania konfliktów Delta Lake pozwalają równoczesnym dopisywaniom na sukces, jednocześnie serializując konfliktujące aktualizacje do tej samej partycji.

Porównanie Podróży w Czasie i Wersjonowania Danych

Oba formaty wspierają podróż w czasie, ale z różną semantyką.

sql
-- Delta Lake: Zapytanie po numerze wersji
SELECT * FROM events VERSION AS OF 42;

-- Delta Lake: Zapytanie po znaczniku czasu
SELECT * FROM events TIMESTAMP AS OF '2026-07-15 10:00:00';

-- Iceberg: Zapytanie po ID snapshota
SELECT * FROM analytics.events FOR SYSTEM_VERSION AS OF 8823749234;

-- Iceberg: Zapytanie po znaczniku czasu
SELECT * FROM analytics.events FOR SYSTEM_TIME AS OF TIMESTAMP '2026-07-15 10:00:00';

Iceberg 1.5+ dodaje branching i tagowanie—można tworzyć nazwane gałęzie do izolowanego eksperymentowania, a następnie scalać lub odrzucać. Delta Lake osiąga podobne przepływy pracy poprzez płytkie klony.

sql
-- Iceberg: Tworzenie gałęzi do testowania
ALTER TABLE analytics.events CREATE BRANCH experiment;

-- Zapis do gałęzi bez wpływu na main
INSERT INTO analytics.events.branch_experiment 
SELECT * FROM staging.events WHERE event_type = 'test';

-- Scalanie gałęzi do main
CALL system.fast_forward('analytics.events', 'main', 'experiment');

Gotowy na rozmowy o Data Engineering?

Ćwicz z naszymi interaktywnymi symulatorami, flashcards i testami technicznymi.

Macierz Kompatybilności Silników Zapytań

Kompatybilność silników napędza wybór formatu dla wielu organizacji.

| Silnik | Wsparcie Delta Lake | Wsparcie Iceberg | |--------|-------------------|------------------| | Apache Spark | Natywne (Databricks, OSS) | Natywne | | Trino/Presto | Konektor | Natywne | | Apache Flink | Konektor | Natywne (1.16+) | | Dremio | Tylko odczyt | Natywne | | AWS Athena | Ograniczone | Natywne | | Snowflake | Tabele zewnętrzne | Natywne (tabele Iceberg) | | BigQuery | Tabele zewnętrzne | BigLake Iceberg |

Dla środowisk tylko-Spark, ściślejsza integracja Delta Lake oferuje lepszą wydajność. Architektury wielosilnikowe korzystają z szerszej kompatybilności Iceberg—REST Catalog Iceberg zapewnia neutralny dla dostawcy interfejs API do operacji katalogowych.

Techniki Optymalizacji Wydajności

Oba formaty wymagają operacji konserwacyjnych dla optymalnej wydajności zapytań.

python
# delta_optimize.py
from delta import DeltaTable

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

# Kompaktowanie małych plików (bin-packing)
delta_table.optimize().executeCompaction()

# Z-order dla predykatów wielokolumnowych
delta_table.optimize().executeZOrderBy("user_id", "event_time")

# Usuwanie starych wersji (vacuum)
delta_table.vacuum(retentionHours=168)  # Zachowaj 7 dni
sql
-- Iceberg: Przepisanie plików danych dla kompaktowania
CALL catalog.system.rewrite_data_files(
  table => 'analytics.events',
  strategy => 'binpack',
  options => map('target-file-size-bytes', '134217728')
);

-- Iceberg: Wygaszanie starych snapshotów
CALL catalog.system.expire_snapshots(
  table => 'analytics.events',
  older_than => TIMESTAMP '2026-07-01 00:00:00',
  retain_last => 10
);

Z-ordering grupuje powiązane dane razem, poprawiając efektywność predicate pushdown. Oba formaty korzystają z kompaktowania plików podczas ingestowania wielu małych plików ze źródeł strumieniowych.

Typowe Pytania Rekrutacyjne o Data Lakehouse

Przygotowanie do często zadawanych pytań na rozmowach kwalifikacyjnych dla inżynierów danych.

P: Kiedy wybrałbyś Iceberg zamiast Delta Lake?

Iceberg pasuje lepiej gdy: (1) wiele silników zapytań uzyskuje dostęp do tych samych tabel (Spark, Trino, Flink), (2) schematy partycji muszą ewoluować bez przepisywania danych, (3) organizacja preferuje neutralne dla dostawcy otwarte standardy. Delta Lake sprawdza się w architekturach skoncentrowanych na Databricks lub czystych środowiskach Spark, gdzie Unity Catalog zapewnia governance.

P: Jak Iceberg osiąga ewolucję partycji bez przepisywania danych?

Iceberg przechowuje specyfikacje partycji jako metadane. Gdy specyfikacja się zmienia, nowe dane używają nowego partycjonowania, podczas gdy istniejące dane zachowują oryginalny układ. Planer zapytań odczytuje wszystkie specyfikacje partycji i stosuje odpowiednią logikę przycinania dla każdej grupy plików.

P: Wyjaśnij mechanizm checkpointów Delta Lake.

Delta Lake tworzy pliki checkpoint domyślnie co 10 commitów. Checkpoint konsoliduje dziennik transakcji w pojedynczy plik Parquet dla szybszego odczytu. Plik _last_checkpoint wskazuje na najnowszy checkpoint, a czytelnicy rekonstruują stan odczytując checkpoint plus wszelkie kolejne commity JSON.

P: Czym jest copy-on-write vs merge-on-read?

Copy-on-write (COW) przepisuje całe pliki przy aktualizacjach—wyższy koszt zapisu, ale szybsze odczyty. Merge-on-read (MOR) zapisuje delty osobno, scalając w czasie zapytania—niższe opóźnienie zapisu, ale narzut odczytu. Iceberg wspiera oba podejścia; Delta Lake głównie używa COW z deletion vectors dla miękkich usunięć w najnowszych wersjach.

Te wzorce warto przećwiczyć na pytaniach rekrutacyjnych z inżynierii danych na SharpSkill, aby utrwalić zrozumienie przed rozmowami kwalifikacyjnymi.

Ścieżka Migracji: Konwersja Między Formatami

Organizacje czasami muszą migrować między formatami. Oba wspierają narzędzia do konwersji.

python
# Konwersja Delta do Iceberg używając Spark
spark.sql("""
    CALL catalog.system.snapshot(
        source_table => 'delta.`s3://bucket/delta_events`',
        table => 'analytics.events_iceberg'
    )
""")

# Konwersja Iceberg do 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")

Pełna migracja wymaga starannej walidacji typów schematu, semantyki partycjonowania i kompatybilności konsumentów downstream.

Podsumowanie

  • Delta Lake sprawdza się najlepiej dla obciążeń natywnych Spark, środowisk Databricks i gdy Unity Catalog governance pasuje do potrzeb organizacji
  • Iceberg należy wybierać dla architektur wielosilnikowych, wymagań ewolucji partycji i wdrożeń niezależnych od chmury
  • Oba formaty dostarczają transakcje ACID, podróż w czasie i ewolucję schematu—właściwy wybór zależy od istniejącej infrastruktury i różnorodności silników zapytań
  • Przygotowanie do rozmów rekrutacyjnych powinno obejmować wewnętrzne działanie dziennika transakcji, optymalizację przycinania partycji oraz kompromisy COW vs MOR
  • Kompaktowanie plików i wygaszanie snapshotów pozostają krytycznymi zadaniami konserwacyjnymi niezależnie od wyboru formatu

Zacznij ćwiczyć!

Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.

Tagi

#delta-lake
#apache-iceberg
#data-lakehouse
#inżynieria-danych
#rozmowa-kwalifikacyjna

Udostępnij

Powiązane artykuły