Open Table Formats Iceberg
Complete the full lesson to earn 25 points
Work through each section, then tap “Mark as Complete” on the last one.
✦ Skip the page breaks and see fewer ads — read each lesson on a single page with Pro
Mastering Apache Iceberg: The Modern Data Lakehouse Foundation
Introduction: The Evolution of Data Storage
For decades, data engineers and architects have faced a fundamental trade-off: the performance and consistency of a traditional relational database (OLTP/OLAP) versus the scalability and cost-efficiency of a data lake. In the early days of big data, we stored raw files—usually CSV, JSON, or Parquet—in object storage like Amazon S3 or HDFS. While this allowed us to store petabytes of information cheaply, it came with a significant cost: the lack of transactional integrity. If a job failed halfway through writing a file, you were left with partial data, and there was no easy way to perform updates or deletions without rewriting entire datasets.
Apache Iceberg emerged as a solution to bridge this gap, functioning as an "open table format" for massive analytic datasets. An open table format acts as a metadata layer that sits on top of your data files, providing the features we expect from a database—ACID transactions, schema evolution, and time travel—while keeping the data in open, standardized file formats like Parquet, Avro, or ORC. Understanding Iceberg is essential for any modern data practitioner because it transforms a messy, unmanaged data lake into a reliable, high-performance data warehouse, often referred to as a "Data Lakehouse."
In this lesson, we will explore the architecture of Apache Iceberg, understand how it handles metadata, learn how to implement it in your workflows, and discuss the best practices that keep your data store performant and cost-effective.
The Core Problem: Why Do We Need Iceberg?
To understand the value of Iceberg, we first need to look at the limitations of the traditional "Hive-style" partitioning. In a standard data lake, tables are organized as directories. If you have a table partitioned by date, your file system might look like /data/table/date=2023-10-01/. To query this data, an engine like Spark or Trino must list every file in that directory.
As your data grows, this "listing" process becomes a bottleneck. Furthermore, if you want to update a single row, you have to rewrite the entire partition, which is incredibly inefficient. Iceberg solves these problems by moving the source of truth from the file system directory structure to a centralized metadata file.
Key Architectural Components
Iceberg tracks data at the file level rather than the directory level. It uses a tree-like metadata structure to manage this:
- Iceberg Catalog: The pointer that keeps track of the current "metadata pointer" for a table. It ensures that every user is looking at the same version of the data.
- Metadata File: This file contains the table schema, partition information, and a snapshot ID. It represents a specific version of the table.
- Manifest List: A list of manifest files that make up a snapshot. It contains statistics about each manifest, such as the range of partition values.
- Manifest File: A list of actual data files (e.g., Parquet files) along with details about the data they contain, such as column-level min/max values.
Callout: The Metadata Advantage Unlike traditional Hive tables, where the file system is the metadata, Iceberg treats files as first-class citizens. Because Iceberg knows the min/max values for every column in every file, it can perform "pruning" at a much deeper level. If you query for
WHERE id = 500, Iceberg can instantly skip over 99% of your files because it knows which files contain that specific value, without ever needing to list the contents of a directory.
Setting Up and Interacting with Iceberg
Iceberg is designed to be engine-agnostic. Whether you are using Apache Spark, Trino, Flink, or Dremio, the underlying data remains the same. The implementation typically happens through the SQL interface provided by these engines.
Creating an Iceberg Table in Spark
When working with Spark, the most common way to create an Iceberg table is through the standard CREATE TABLE syntax, provided you have configured your catalog correctly.
-- Create a table using the Iceberg format
CREATE TABLE prod.db.events (
event_id bigint,
event_time timestamp,
user_id bigint,
event_type string
) USING iceberg
PARTITIONED BY (days(event_time));
In this example, notice the USING iceberg clause and the hidden partitioning days(event_time). In a traditional system, you would need to create a separate column for the date and manually map your timestamps to that column. Iceberg handles this automatically. If you query by event_time, Iceberg will automatically map it to the correct partition, preventing common errors where users query the wrong partition column.
Inserting and Updating Data
Once the table is created, interacting with it feels exactly like working with a standard SQL database.
-- Inserting data
INSERT INTO prod.db.events
VALUES (1, '2023-10-01 10:00:00', 101, 'click'),
(2, '2023-10-01 11:00:00', 102, 'view');
-- Updating data
UPDATE prod.db.events
SET event_type = 'purchase'
WHERE event_id = 1;
When you run the UPDATE command, Iceberg does not rewrite the entire table. Instead, it performs a "copy-on-write" or "merge-on-read" operation. It identifies the file containing the row, creates a new version of that file with the update, and then updates the metadata to point to the new file while marking the old one as "deleted" in the context of the new snapshot.
Note: Copy-on-write is great for read-heavy workloads because it produces highly optimized files. Merge-on-read is better for write-heavy workloads, as it writes changes to smaller "delete files" that are merged with the main data at query time.
Advanced Features: Time Travel and Schema Evolution
One of the most powerful aspects of Iceberg is its ability to handle schema changes and historical data access without requiring complex migrations.
Schema Evolution
In traditional data lakes, adding a column or renaming one often requires rewriting the entire dataset. In Iceberg, this is a metadata-only operation.
-- Adding a column
ALTER TABLE prod.db.events ADD COLUMN user_location string AFTER user_id;
-- Renaming a column
ALTER TABLE prod.db.events RENAME COLUMN event_type TO action_type;
Because these changes only modify the metadata files and not the underlying Parquet files, they are virtually instantaneous regardless of whether your table has 100 rows or 100 billion rows.
Time Travel
Since Iceberg keeps a history of snapshots, you can query the state of your data as it existed at any point in the past. This is invaluable for debugging data pipelines or auditing data changes.
-- Querying data as it existed yesterday
SELECT * FROM prod.db.events.history; -- View all snapshots
-- Querying a specific snapshot
SELECT * FROM prod.db.events VERSION AS OF 1234567890123456789;
Best Practices for Performance and Maintenance
While Iceberg automates much of the complexity, you must still maintain the table to ensure performance doesn't degrade over time. The primary concern is the accumulation of small files and metadata.
1. Compaction
If you are performing many small updates or streaming data into your table, you will inevitably end up with a large number of small files. Small files are the enemy of query performance because they increase the overhead of opening and closing file handles.
You should run a compaction job periodically:
CALL prod.system.rewrite_data_files(table => 'prod.db.events');
2. Expiring Snapshots
Iceberg keeps snapshots indefinitely by default. If you don't clean them up, your metadata storage will grow indefinitely, and your storage costs will rise. You should set up a retention policy to remove old snapshots.
-- Keep only the last 7 days of snapshots
CALL prod.system.expire_snapshots(
table => 'prod.db.events',
older_than => TIMESTAMP '2023-10-24 00:00:00'
);
3. Orphan File Removal
Sometimes, failed jobs or manual deletions leave behind files that are no longer referenced in the current metadata. These files consume storage space for no reason. Use the remove_orphan_files procedure to clean these up.
Warning: Never delete files from the underlying storage (S3/GCS/Azure Blob) manually. Always use the Iceberg system procedures. Deleting files manually will corrupt your table because the Iceberg metadata will still think those files exist, leading to query failures.
Comparison Table: Data Storage Formats
| Feature | Hive (Standard) | Apache Iceberg |
|---|---|---|
| ACID Transactions | No | Yes |
| Partitioning | Manual (Folder-based) | Hidden (Automatic) |
| Schema Evolution | Risky/Limited | Full (Metadata-only) |
| Time Travel | No | Yes |
| File Listing | Slow (O(N) operations) | Fast (O(1) metadata lookups) |
| Update/Delete | Requires full rewrite | Row-level support |
Common Pitfalls and How to Avoid Them
Pitfall 1: Over-partitioning
In the Hive era, people often partitioned by extremely granular columns, like hour or even minute. While this helped with query performance in Hive, it creates an enormous number of small files in Iceberg and puts unnecessary pressure on the metadata layer.
- Solution: Use Iceberg’s hidden partitioning. Let Iceberg handle the mapping, and stick to coarser partitions (e.g.,
daysormonths) unless you have a very specific reason not to.
Pitfall 2: Neglecting Maintenance
Many teams set up Iceberg and forget about it. Over time, the metadata grows, and the number of small files increases, leading to "metadata bloat" and slow queries.
- Solution: Integrate compaction and snapshot expiration into your automated orchestration layer (Airflow, Dagster, etc.). Treat table maintenance as a routine task, just like you would with a traditional database.
Pitfall 3: Incorrect Catalog Configuration
Iceberg relies on a catalog to provide a single view of the table. If you have multiple engines (e.g., Spark and Trino) pointing to different catalogs for the same underlying data, you will experience inconsistencies and potential data loss.
- Solution: Use a centralized catalog service (like AWS Glue, Hive Metastore, or Nessie) that all your compute engines point to. Consistency at the catalog level is the bedrock of Iceberg's reliability.
Deep Dive: How Iceberg Handles ACID Transactions
The "ACID" in Iceberg stands for Atomicity, Consistency, Isolation, and Durability. Let's look at how this is achieved through the metadata pointer.
When an engine (like Spark) wants to write data, it performs the following steps:
- Write Data: It writes new data files to the storage.
- Create Manifests: It creates new manifest files that point to these new data files.
- Create Snapshot: It creates a new metadata file that points to the new manifest list.
- Commit: It attempts to update the "current snapshot" pointer in the catalog.
The "Commit" step is the most critical. Iceberg uses an atomic "compare-and-swap" (CAS) operation at the catalog level. If two processes try to update the pointer at the same time, the catalog will reject one of them, forcing a retry. This ensures that the table state is never corrupted, even if multiple jobs are writing to the table simultaneously. This level of concurrency control was virtually impossible to manage reliably in standard file-based data lakes.
Callout: Optimistic Concurrency Control Iceberg uses Optimistic Concurrency Control (OCC). It assumes that conflicts are rare. If a conflict does occur, the operation fails and the engine is expected to retry the transaction. This is highly efficient for high-throughput data pipelines where most jobs are writing to different partitions or different files, preventing the locking overhead found in traditional relational databases.
Integrating Iceberg with Your Data Pipeline
A typical modern data pipeline looks like this:
- Ingestion: Raw logs arrive in an S3 bucket.
- Transformation (Bronze to Silver): An ETL job reads raw data, cleans it, and writes it to an Iceberg "Silver" table.
- Refinement (Silver to Gold): An aggregation job reads the Silver table and performs joins or aggregations, writing to an Iceberg "Gold" table.
- Maintenance: A separate service runs periodically to expire snapshots and compact files.
Because Iceberg tables are essentially just files in S3, you can easily implement "branching" and "tagging" (if your catalog supports it, like Project Nessie). This allows you to test new transformations on a branch of the table without affecting the production data, providing a software-engineering-like workflow for data.
Step-by-Step: Migrating an Existing Table
If you have an existing Hive-style table and want to move it to Iceberg, you don't necessarily have to rewrite everything at once.
- Create the Iceberg Table: Use the same schema as your existing table.
- Migrate Data: Use the
migrateprocedure provided by Iceberg to convert the existing files in-place.CALL prod.system.migrate('prod.db.old_table'); - Verify: Run a count comparison between the old table and the new Iceberg table.
- Point Consumers: Update your downstream reports or dashboards to point to the new Iceberg table.
Note: The migrate procedure is a powerful tool, but always perform a dry run on a subset of data first to ensure your schema and partitioning translate correctly.
Industry Standards and Future Trends
The industry is rapidly converging on Iceberg as the standard for open data lake storage. Major cloud providers (AWS, Google, Azure) have all integrated Iceberg into their managed analytic services (Athena, BigQuery, Synapse). This means that by using Iceberg, you are avoiding "vendor lock-in." If you decide to move your compute from AWS Athena to Google BigQuery, you can take your data with you without any migration effort, because the underlying format is open and accessible.
We are also seeing the rise of "Table Format Governance." Tools are being built to scan Iceberg metadata to provide data lineage, audit logs, and fine-grained access control. As the ecosystem matures, the distinction between "Data Warehouse" and "Data Lake" will continue to blur, making Iceberg the de facto foundation for any storage strategy that values flexibility and scale.
Frequently Asked Questions (FAQ)
Q: Is Iceberg slower than Parquet? A: No, Iceberg is Parquet (or Avro/ORC). It is just a metadata layer sitting on top. Because Iceberg provides better statistics for pruning, queries on Iceberg tables are often faster than queries on raw Parquet files.
Q: Can I read Iceberg tables without a catalog? A: You need a catalog to find the current metadata pointer. While you could technically find the latest metadata file by listing the "metadata" directory in your storage, it is not recommended and is prone to errors. Always use a catalog.
Q: How do I handle large-scale deletes?
A: If you need to delete a massive amount of data, use the DELETE FROM statement. Iceberg will handle the metadata updates. If you are doing bulk deletions (e.g., removing a year of data), it is often more efficient to rewrite the table or use partition-level operations if possible.
Q: Does Iceberg support streaming? A: Yes, Iceberg is excellent for streaming. With tools like Apache Flink, you can write to an Iceberg table in real-time. Flink will handle the commits to the Iceberg catalog, making the data available for read-only queries almost immediately.
Key Takeaways
- Metadata is the Key: Apache Iceberg moves the source of truth from the file system directory structure to a robust, versioned metadata layer, enabling ACID transactions and reliable querying.
- Engine Agnostic: Iceberg is designed to be used by any compute engine (Spark, Trino, Flink), ensuring that your data remains portable and free from vendor lock-in.
- Maintenance is Mandatory: While Iceberg automates many tasks, you must actively manage snapshot expiration and file compaction to prevent performance degradation and storage cost inflation.
- Schema and Partition Flexibility: Through hidden partitioning and metadata-only schema evolution, Iceberg allows you to change your table structure without the expensive task of rewriting underlying data files.
- Time Travel for Reliability: The ability to query historical versions of your data is a game-changer for debugging, auditing, and recovering from accidental data corruption.
- Avoid Manual File Manipulation: Never interact with the physical files in your storage layer directly. Use the Iceberg SQL API for all operations, including data deletion and maintenance, to keep your metadata consistent.
- Choose the Right Strategy: Understand the difference between Copy-on-Write and Merge-on-Read to optimize your table based on whether your workload is read-heavy or write-heavy.
By mastering these concepts, you shift your role from a "file manager" to a "data architect." You are no longer just storing bytes in the cloud; you are building a high-performance, reliable system that can handle the complexities of modern data science and analytics with ease. Take the time to implement these practices in your development environments, and you will find that your data storage becomes one of the most reliable components of your entire infrastructure.
Continue the course
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles your daily points limit so you progress twice as fast, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× daily points limit
- ✓ Distraction-free lessons