Delta Lake Overview and Interview Atlas
Answer First: Delta Lake is an open table format and transaction layer that records table state in a transaction log while storing data in data files such as Parquet.
Memory Map: data files + transaction log -> snapshot -> reliable table operations.
Version and product-name guardrails
- Separate open-source Delta Lake behavior from Databricks-only SQL commands and managed services. Check the Delta Lake release index and the target runtime before making a version claim.
- A checkpoint every 10 commits is a common default, not a protocol guarantee:
delta.checkpointIntervalis configurable, and connector applications decide when to checkpoint: official Delta Kernel guide. - Time travel does not preserve files independently of retention. VACUUM can remove files needed by old snapshots or long-running readers; inspect history and active workloads before shortening retention.
- Liquid clustering is incremental because
OPTIMIZErewrites only data needed for clustering; it does not mean βnew data onlyβ. It is incompatible with partitioning andZORDER, and runtime support is versioned: official guide. - βStatistics on the first 32 columnsβ is the current default for Unity Catalog external tables, not a universal Delta limit. Managed-table statistics can be selected by predictive optimization, and explicit statistics columns are configurable: official guide.
- Protocol, table-feature, CDF, deletion-vector, UniForm, clustering, and schema-evolution support is version-sensitive. Validate reader and writer compatibility before enabling a feature.
- Performance percentages and file-size targets in the legacy notes are workload hypotheses, not guarantees; verify with table history, operation metrics, query plans, and representative benchmarks.
Canonical Delta Lake module map
Use the chapter navigation in order, or jump from the link-only question index to the exact concept owner.
Delta Lake & Lakehouse Architecture
Focus: Transaction log, MERGE scenarios, optimization, architecture decisions Complete Delta Guide: For the full standalone Delta Lake page (32 questions), see /learn/delta
Memory Map
Answer First: A managed table uses a platform-managed storage location and lifecycle, while an external table registers data at a user-controlled location. Dropping the registration therefore has different data-retention consequences.
Memory Map: the difference between managed and external tables in Databricks -> storage owner defines responsibility -> registration chooses managed or external lifecycle -> DROP and retention behavior follow ownership -> location metadata proves the boundary [03_Delta_Lake_and_Lakehouse.md:596].
Q19: What is the difference between managed and external tables in Databricks?
Answer:
| Aspect | Managed Table | External Table |
|---|---|---|
| Storage | Databricks-managed location | User-specified external location |
| DROP TABLE | Deletes both metadata AND data | Deletes only metadata β data survives |
| Use case | Default for most tables | Shared data, data must survive table drops |
| Unity Catalog | Managed by metastore | Requires External Location grant |
-- Managed (data stored in default warehouse location)
CREATE TABLE managed_orders (id LONG, amount DECIMAL);
-- External (data at your specified location)
CREATE TABLE external_orders (id LONG, amount DECIMAL)
LOCATION 's3://my-bucket/orders/';
SECTION 5: LAKEHOUSE ARCHITECTURE
Answer First: A lakehouse keeps open object storage and adds ACID transaction metadata, governance, and warehouse-style performance. Unlike a raw data lake it provides reliable table semantics, while unlike a traditional warehouse it preserves open files and separates storage from compute.
Memory Map: a data lakehouse? How does it differ from data lake and data warehouse -> data lakehouse it differ from data lake and data warehouse sets the specific transaction and interoperability constraint -> engine ecosystem defines interoperability needs -> mutation model selects transaction semantics -> maintenance ownership sets operating cost -> cross-engine test determines fit [03_Delta_Lake_and_Lakehouse.md:677].
Q22: What is a data lakehouse? How does it differ from data lake and data warehouse?
Simple Explanation:
- Data Lake = Big messy warehouse (cheap rent, hard to find things, no ACID)
- Data Warehouse = Expensive organized office (everything in place, but high rent, vendor lock-in)
- Data Lakehouse = Organized warehouse (cheap rent + everything labeled and easy to find + ACID + open format)
The Lakehouse combines the BEST of both: cheap object storage (like a lake) + ACID transactions and fast BI queries (like a warehouse).
Answer:
| Aspect | Data Lake | Data Warehouse | Data Lakehouse |
|---|---|---|---|
| Storage | Cheap object storage | Proprietary | Cheap object storage |
| Format | Open (Parquet, ORC) | Proprietary | Open (Delta, Iceberg, Hudi) |
| ACID | No | Yes | Yes |
| Schema | Schema-on-read | Schema-on-write | Both |
| Performance | Slow for BI | Fast for BI | Fast (OPTIMIZE, caching, Photon) |
| ML support | Good | Poor | Excellent |
| Governance | Limited | Strong | Strong (Unity Catalog) |
| Cost | Low | High | Low-Medium |
Answer First: Delta Lake / Iceberg / Hudi: ACID transactions on data lakes.
Memory Map: What key technologies enable the lakehouse -> open object storage preserves interoperable files -> transaction metadata adds reliable mutation -> scalable compute serves SQL and ML -> centralized governance joins both workloads [03_Delta_Lake_and_Lakehouse.md:700].
Q23: What key technologies enable the lakehouse?
Answer:
- Delta Lake / Iceberg / Hudi: ACID transactions on data lakes
- Photon / vectorized engines: Warehouse-level query performance
- Unity Catalog: Unified governance across all data assets
- Serverless compute: On-demand, auto-scaling
- SQL endpoints / SQL Warehouses: Direct BI tool connectivity
- MLflow: Integrated ML lifecycle management
Answer First: Eliminates the "two-tier" architecture (data lake + data warehouse).
Memory Map: What problems does the lakehouse solve -> single governed copy removes lake-to-warehouse duplication -> reliable tables support updates and concurrency -> independent compute serves varied workloads -> shared lineage reduces operational fragmentation [03_Delta_Lake_and_Lakehouse.md:712].
Q24: What problems does the lakehouse solve?
Answer:
- Eliminates the "two-tier" architecture (data lake + data warehouse)
- No more ETL from lake to warehouse
- Single copy of data serves all workloads
- Reduces data duplication and ETL complexity
- Single source of truth for BI and ML
- Open formats prevent vendor lock-in
- Cost-effective storage with warehouse-level performance
- Unified governance across all workloads
Interview Tip: "When asked 'Why Databricks over Snowflake?', mention: open formats (no vendor lock-in), unified BI + ML on one platform, Delta Lake is open source, and Photon gives warehouse-level speed on open data."
What NOT to Say: "Lakehouse means storing everything in one table" β No, it's an ARCHITECTURE pattern (Bronze/Silver/Gold layers) on cheap storage with ACID.
Answer First: DataFrame overwrite replaces table data within the write scope, whereas REPLACE TABLE atomically replaces the table definition and data. The required schema and metadata transition determine which operation is correct.
Memory Map: the difference between DataFrame.write.mode("overwrite") and REPLACE TABLE in Delta -> difference between dataframe write mode overwrite and replace table in delta applies a distinct transaction-log action set -> starting table version defines state -> metadata and file actions apply the operation -> atomic commit publishes a new snapshot -> history and metrics verify the transition [03_Delta_Lake_and_Lakehouse.md:818].
Q28: What is the difference between DataFrame.write.mode("overwrite") and REPLACE TABLE in Delta?
Answer:
| Aspect | mode("overwrite") | REPLACE TABLE |
|---|---|---|
| Scope | Overwrites data (optionally per partition) | Replaces entire table definition |
| Schema | Keeps existing schema (unless overwriteSchema=true) | Can change schema |
| History | Maintains history (time travel works) | Maintains history |
| Partition overwrite | Supports replaceWhere for surgical overwrites | N/A |
# Overwrite specific partitions only
df.write.format("delta") \
.mode("overwrite") \
.option("replaceWhere", "date = '2025-01-15'") \
.saveAsTable("orders")
# This is IDEMPOTENT β safe for retry/re-run
Answer First: WAP ensures data quality before making data visible to consumers.
Memory Map: you implement write-audit-publish (WAP) pattern with Delta Lake -> writer creates an isolated candidate table -> validation checks quality and reconciliation -> atomic promotion changes the consumer pointer -> failed checks leave published state untouched [03_Delta_Lake_and_Lakehouse.md:840].
Q29: How do you implement write-audit-publish (WAP) pattern with Delta Lake?
Answer: WAP ensures data quality before making data visible to consumers.
# Step 1: Write to a staging area (or use table clones)
staging = "staging_orders"
df.write.format("delta").mode("overwrite").saveAsTable(staging)
# Step 2: Audit β run quality checks
quality_check = spark.sql(f"""
SELECT
COUNT(*) as total_rows,
SUM(CASE WHEN order_id IS NULL THEN 1 ELSE 0 END) as null_ids,
SUM(CASE WHEN amount < 0 THEN 1 ELSE 0 END) as negative_amounts
FROM {staging}
""").collect()[0]
assert quality_check["null_ids"] == 0, "Null order IDs found!"
assert quality_check["negative_amounts"] == 0, "Negative amounts found!"
# Step 3: Publish β atomically swap
spark.sql(f"""
INSERT OVERWRITE TABLE production_orders
SELECT * FROM {staging}
""")
Alternative with Delta's RESTORE:
If quality check fails after writing to production, RESTORE TABLE production_orders TO VERSION AS OF .
Delta Lake & Lakehouse Deep Dive
Answer First: MERGE must resolve at most one source row for each target row that an update or delete clause changes. Deduplicate the source deterministically by business key and ordering column before the match.
Memory Map: What happens when source has duplicate keys? How to fix -> multiple changes for one target make mutation ambiguous -> deterministic ordering ranks candidate rows -> deduplication retains one winner per key -> uniqueness assertion runs before commit [DB_01_Delta_Lake_Deep_Dive.md:187].
Q6: What happens when source has duplicate keys? How to fix?
Simple Explanation: MERGE requires that each target row matches at most ONE source row. If your source data has duplicate booking_ids (e.g., two records for booking ABC123), MERGE doesn't know which one to use β it throws an error.
The fix: Deduplicate the source data BEFORE merging. Keep only the latest record per key.
-- Problem: bookings_staging has 2 rows for booking_id = 'ABC123'
-- Solution: Use ROW_NUMBER to keep only the latest one
WITH deduped AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY booking_id -- Group by booking_id
ORDER BY updated_at DESC -- Latest record first
) AS rn -- rn=1 means the latest record
FROM bookings_staging
)
SELECT * FROM deduped WHERE rn = 1 -- Keep only the latest record per booking
Why duplicates happen in real life:
- Source system sent the same event twice (retry)
- Multiple Kafka partitions delivered the same record
- File was reprocessed accidentally
SECTION 5: LAKEHOUSE ARCHITECTURE (30 min)
Q15: What is a Data Lakehouse? How is it different from Data Lake and Data Warehouse?
Simple Explanation:
Data Lake = Cheap cloud storage (like ADLS Gen2 or S3) where you dump all your raw data in any format (JSON, CSV, Parquet). It's cheap and flexible, but messy β no ACID transactions, no schema enforcement, slow for BI queries.
Data Warehouse = Expensive, structured database (like Azure Synapse, Snowflake) optimized for BI queries. Fast and well-governed, but expensive and bad for ML/unstructured data.
Data Lakehouse = The BEST of both. It takes the cheap storage of a data lake, adds Delta Lake for ACID transactions and schema enforcement, adds Photon for fast BI queries, and adds Unity Catalog for governance. You get data lake flexibility + data warehouse reliability at data lake prices.
Real-world analogy:
- Data Lake = Big messy warehouse (cheap rent, hard to find things)
- Data Warehouse = Expensive organized office (everything in place, but high rent)
- Lakehouse = Organized warehouse (cheap rent + everything labeled and easy to find)
| Aspect | Data Lake | Data Warehouse | Lakehouse |
|---|---|---|---|
| Storage cost | Cheap (ADLS/S3) | Expensive (proprietary) | Cheap (ADLS/S3) |
| File format | Open (Parquet, JSON) | Proprietary (locked in) | Open (Delta, Iceberg) |
| ACID transactions | No (data can get corrupted) | Yes | Yes (Delta Lake) |
| Schema | Schema-on-read (messy) | Schema-on-write (strict) | Both (flexible) |
| BI query speed | Slow | Fast | Fast (Photon engine) |
| ML support | Good | Poor | Excellent |
| Governance | Limited | Strong | Strong (Unity Catalog) |
Q16: What technologies make the Lakehouse possible?
These are the key building blocks β know what each one does:
- Delta Lake β Adds ACID transactions to cloud storage (the foundation of lakehouse)
- Photon Engine β C++ query engine that makes queries as fast as a data warehouse (see Day 3)
- Unity Catalog β Centralized governance β who can access what data (see Day 3)
- Serverless SQL Warehouses β BI tools (Power BI, Tableau) connect directly to Databricks
- MLflow β Manage the ML lifecycle (track experiments, deploy models)
- Lakeflow Declarative Pipelines β Build ETL pipelines with built-in data quality checks (see Day 2)
Interview tip: When asked "Why Databricks over Snowflake?", mention: open formats (no vendor lock-in), unified BI + ML on one platform, Delta Lake is open source, and Photon gives warehouse-level speed on open data.
SECTION 6: NEW 2025-2026 FEATURES (30 min)
Answer First: Delta 4.x adds capabilities such as Variant for semi-structured values, type widening, and newer protocol features. Each feature must be checked against the Spark, Java, reader, and writer compatibility boundary before adoption.
Memory Map: What's new in Delta Lake 4.x? (Mention 2-3 in interview to show you're up to date) -> Variant stores semi-structured values under protocol support -> widening permits selected safe type changes -> feature adoption may raise reader or writer requirements -> compatibility matrix gates rollout [DB_01_Delta_Lake_Deep_Dive.md:655].
Q17: What's new in Delta Lake 4.x? (Mention 2-3 in interview to show you're up to date)
| Feature | Version | Simple Explanation |
|---|---|---|
| Variant Data Type | 4.0 | Store messy JSON data without defining a schema first. Useful when source sends unpredictable JSON structures. |
| Type Widening | 4.0 | Change a column type (e.g., INT β BIGINT) without rewriting all data files. Before this, you had to recreate the table! |
| Coordinated Commits | 4.0 | Multiple writers from different systems can write to the same table safely. Useful for multi-cloud setups. |
| Delta Connect | 4.0 | Do Delta operations (MERGE, etc.) remotely over Spark Connect β no need to run on the same cluster. |
| Conflict-Free Deletion Vectors | 4.1 | Enable deletion vectors on a table without blocking other writers. Before, enabling DV required exclusive access. |
| Server-Side Planning | 4.1 | Query planning done by the catalog server instead of the client β faster startup for large tables. |
| Atomic CTAS | 4.1 | CREATE TABLE AS SELECT is now fully atomic β if it fails midway, no partial table is left behind. |
Breaking change: Delta 4.x needs Spark 4.x and Java 17+ (older versions won't work).
Interview tip: Mention Variant Data Type and Type Widening β they solve real problems that interviewers care about.
Answer First: Lakebase is a brand NEW feature (GA on Azure March 2026). It's a serverless PostgreSQL-compatible database built into Databricks.
Memory Map: Lakebase -> managed PostgreSQL service handles low-latency row transactions -> application reads and writes operational state -> governed integration exposes data to analytics -> replication lag measures freshness [DB_01_Delta_Lake_Deep_Dive.md:692].
Q19: What is Lakebase?
Simple Explanation: Lakebase is a brand NEW feature (GA on Azure March 2026). It's a serverless PostgreSQL-compatible database built into Databricks.
Why does it exist? Delta Lake is great for analytics (batch queries, BI), but NOT great for low-latency application queries (like "get this passenger's details in 10 ms for the mobile app"). Lakebase fills this gap β it's a real database for application use cases, running inside Databricks.
Key features:
- Scale-to-zero: When nobody is querying, it costs $0 (shuts down automatically)
- Database branching: Create an instant copy of your database for testing (like git branch for databases!)
- Instant restore: Go back to any point in time if something goes wrong
- Auto-failover HA: If one server fails, another takes over automatically
When to use Lakebase vs Delta tables:
| Use Case | Lakebase | Delta Table |
|---|---|---|
| App backend (API serving, low-latency lookups) | β Best choice | β Too slow |
| Batch analytics (BI, reporting) | β Not designed for this | β Best choice |
| Feature serving for ML models | β Good (low-latency) | β Good (batch) |
| Application backend (CRUD operations) | β Best choice | β Not designed for this |
Q20: What is the difference between Managed and External tables?
Simple Explanation: When you create a table in Unity Catalog, you choose where the data is stored:
Managed Table: Databricks decides where to store the data (in a Databricks-managed location). If you DROP the table, BOTH the metadata AND the data are deleted. Simple and recommended for most cases.
External Table: YOU specify where the data lives (e.g., a specific ADLS Gen2 path). If you DROP the table, only the metadata is removed β the actual data files survive. Use this when data must persist even if the table definition is removed, or when data is shared with other systems.
Real-world analogy:
- Managed = Renting a furnished apartment. If you end the lease, furniture goes too.
- External = Renting an empty apartment and bringing your own furniture. If you end the lease, you take your furniture with you.
| Aspect | Managed Table | External Table |
|---|---|---|
| Where data lives | Databricks-managed location (auto) | Your ADLS Gen2 path (you specify) |
| DROP TABLE | Deletes metadata AND data | Deletes metadata ONLY β data survives |
| Predictive Optimization | β Works automatically | β Not supported |
| Best for | Most tables (default choice) | Data shared with other systems, legacy data |
| Governance | Full Unity Catalog governance | Needs External Location + Storage Credential setup |
-- Managed table (recommended for new tables β simpler to manage)
CREATE TABLE travel_catalog.bookings.flights (
flight_id LONG, -- Unique flight identifier
departure STRING, -- Departure airport code (e.g., BLR)
arrival STRING -- Arrival airport code (e.g., DEL)
);
-- Databricks stores data in its managed location automatically
-- DROP TABLE will delete everything
-- External table (for data that must survive table drops)
CREATE TABLE travel_catalog.bookings.legacy_flights (
flight_id LONG,
departure STRING,
arrival STRING
) LOCATION 'abfss://container@storage.dfs.core.windows.net/legacy/flights/';
-- Data lives at YOUR ADLS Gen2 path
-- DROP TABLE only removes the table definition, data files stay in ADLS
Example use case: "We use managed tables for new Delta tables (Predictive Optimization works automatically). We use external tables for legacy data migrated from Oracle that other systems also read."
Delta Lake & Lakehouse β Quick Recall
- β‘ = Must remember (95% chance of being asked)
- π = Key concept (core understanding needed)
- β οΈ = Common trap (interviewers love to test this)
- π§ = Memory Map (mnemonic/acronym β memorize this!)
- π = One-liner (flash-card style β cover answer, test yourself)
π§ MASTER MEMORY MAP β Day 1
β‘ MUST KNOW DIRECT QUESTIONS (Cover the answer, test yourself!)
An open-source storage layer that adds ACID transactions, schema enforcement, and time travel on top of Parquet files in a data lake (like ADLS Gen2).
In the _delta_log/ folder β a series of JSON commit files + Parquet checkpoint files.
A folder (_delta_log/) that records every change as a numbered JSON file. It's the single source of truth for the table's current state.
Atomicity (all or nothing), Consistency (schema rules enforced), Isolation (readers don't see partial writes), Durability (committed data survives crashes).
Parquet format. Delta Lake = Parquet files + transaction log. The log is what makes it "Delta."
A Parquet summary of the table state, created every 10 commits. Instead of reading 10,000 JSON files, read 1 checkpoint + recent JSONs.
A small file that tells Delta which checkpoint is the latest β so it doesn't have to scan the entire _delta_log/ folder.
When you start reading a table, you see it as it was at that exact moment β even if someone writes new data while you're reading. You always get a consistent view.
When two writers modify the same files. Example: Writer A and B both UPDATE rows in the same partition β one gets a ConcurrentModificationException and must retry.
Delta stores min/max statistics for each data file. When you query WHERE booking_date = '2026-03-15', Delta skips files where min > March 15 or max < March 15. Reads only relevant files.
First 32 columns. Configurable via delta.dataSkippingNumIndexedCols. β οΈ Put your most-filtered columns FIRST in schema!
π MID-LEVEL QUESTIONS
- Read
_last_checkpointβ find latest checkpoint - Read that checkpoint file (Parquet) β get base state
- Read all JSON commits AFTER the checkpoint β apply recent changes
- Result: current list of valid Parquet data files
- Read only those Parquet files β return query results
- Spark writes new Parquet file(s) to the table folder
- Delta creates a new JSON commit in
_delta_log/with"add"action pointing to the new file(s) - The commit is atomic β either the JSON file is fully written, or it's not
- Delta identifies which Parquet files contain the rows to delete
- Reads those files, removes matching rows, writes NEW Parquet files with remaining rows
- Creates a commit with
"remove"(old files) +"add"(new files) - Old files are NOT physically deleted β they stay until VACUUM cleans them
NO! DELETE only marks files as "removed" in the log. The physical Parquet files remain on disk. You need VACUUM to physically delete them. This is why time travel works β old files are still there.
- Two writers start at same snapshot (version 5)
- Writer A commits first β version 6 (success)
- Writer B tries to commit β Delta checks: "Did A modify the same files I'm modifying?"
- If NO conflict (different files/partitions) β auto-resolve, Writer B becomes version 7
- If YES conflict (same files) β
ConcurrentModificationExceptionβ retry from version 6
| Action | Meaning |
|---|---|
add | New Parquet file added |
remove | Parquet file logically removed |
metaData | Schema or table properties changed |
commitInfo | Who, when, what operation |
β‘ MUST KNOW DIRECT QUESTIONS
A single SQL command that does INSERT + UPDATE + DELETE in one atomic operation. Also called "upsert" (update + insert).
Update existing rows if they match, Insert new rows if they don't. MERGE does this in a single pass.
Yes! Add WHEN MATCHED AND source.deleted = true THEN DELETE β three operations in one command.
UnsupportedOperationException β "Cannot perform MERGE as multiple source rows matched." You MUST deduplicate source first.Use ROW_NUMBER() window function to keep only the latest record per key:
WITH deduped AS (
SELECT *, ROW_NUMBER() OVER (
PARTITION BY booking_id ORDER BY updated_at DESC
) AS rn FROM source_data
)
SELECT * FROM deduped WHERE rn = 1
When source has NEW columns that target doesn't have, MERGE can auto-add them. Enable with:
SET spark.databricks.delta.schema.autoMerge.enabled = true
Or: .option("mergeSchema", "true")
π MID-LEVEL QUESTIONS
- Join: Inner join target with source on the match condition
- Classify: Each row is classified as "matched" or "not matched"
- Write: Rewrite affected data files with updates + append new files for inserts
MERGE must scan the ENTIRE target to find matches. Optimizations:
- Liquid Clustering on merge key β scans only relevant files (biggest win)
- Filter source early β
MERGE INTO target USING (SELECT * FROM source WHERE date = today) - OPTIMIZE before MERGE β fewer small files to scan
- Low shuffle merge β reduces data movement between nodes
- Partition by merge key β prunes irrelevant partitions (old approach)
Problem: In SCD Type 2, when a record changes, you need to:
- Close the old row (set
end_date,is_current = false) - Insert a new row (with new values,
is_current = true)
merge_key column: - For rows to UPDATE:
merge_key = booking_id(matches target) - For rows to INSERT:
merge_key = NULL(never matches β goes to NOT MATCHED β INSERT)
β‘ MUST KNOW DIRECT QUESTIONS
Compacts many small Parquet files into fewer large files (target: ~1 GB each). Faster reads because fewer files to open.
Physically deletes old Parquet files that are no longer referenced by the transaction log. Frees up storage.
7 days (168 hours). Files older than this are deleted. β οΈ Setting it lower breaks time travel!
Yes, but DANGEROUS β breaks time travel and concurrent reads. Only use for GDPR "right to be forgotten":
SET spark.databricks.delta.retentionDurationCheck.enabled = false;
VACUUM bookings RETAIN 0 HOURS;
Sorts data within files by specific columns so that similar values are stored together. When you filter by those columns, Delta reads far fewer files.
The new replacement for partitioning + Z-ORDER (Databricks 2024+). Automatically maintains data layout β no manual OPTIMIZE ZORDER needed. You just define clustering keys at table creation.
NO! They are mutually exclusive. Liquid Clustering replaces partitioning. You must choose one or the other.
Instead of rewriting an entire Parquet file to delete a few rows, Delta marks rows as "deleted" in a small side file. The data file stays untouched. Much faster deletes/updates.
Yes, on Databricks (since 2024). They're a table property: delta.enableDeletionVectors = true.
π MID-LEVEL QUESTIONS
| OPTIMIZE | VACUUM | |
|---|---|---|
| What | Merges small files β big files | Deletes old unused files |
| Goal | Faster reads | Save storage space |
| Data loss? | Never | Old versions become unreadable |
| When to run | After many small writes | After OPTIMIZE (clean up old files) |
| Best practice | Run daily | Run weekly |
| Z-ORDER | Liquid Clustering | |
|---|---|---|
| Era | Old (before 2024) | New (2024+, recommended) |
| Setup | Run manually: OPTIMIZE ... ZORDER BY | Define once: CLUSTER BY at table creation |
| Maintenance | Must re-run after every write | Auto-maintains incrementally |
| With partitioning? | Yes, works with partitions | NO β replaces partitioning |
| Column changes | Must rewrite entire table | ALTER TABLE ... CLUSTER BY (new_cols) β easy |
| Use when | Legacy tables, can't migrate | All new tables (always prefer this) |
- When partition column has HIGH cardinality (>10,000 values) β too many tiny folders
- When table is small (<1 TB) β partitioning adds overhead
- When using Liquid Clustering β they're mutually exclusive
- Rule of thumb: Each partition should be >1 GB. If not, don't partition.
- Each file needs a separate read operation β high I/O overhead
- More files = more metadata in the transaction log β slower planning
- Cloud storage (ADLS) charges per API call β more files = higher cost
- Fix: OPTIMIZE (compaction) or Auto Loader with trigger-based batching
β‘ MUST KNOW DIRECT QUESTIONS
Ability to query previous versions of a table using version numbers or timestamps. Works because old Parquet files are kept until VACUUM removes them.
SELECT * FROM bookings VERSION AS OF 5; or TIMESTAMP AS OF '2026-03-20';
DESCRIBE HISTORY bookings; β shows every version, timestamp, operation, and user.
RESTORE TABLE bookings TO VERSION AS OF 5; β rolls back to version 5. This creates a NEW version (safe, doesn't rewrite history).
After VACUUM runs β it physically deletes old files. Default retention is 7 days. If you VACUUM with 0 hours, ALL old versions are gone immediately.
SECTION 5: LAKEHOUSE ARCHITECTURE
π§ Memory Map: Lakehouse
β‘ MUST KNOW DIRECT QUESTIONS
A single platform combining the cheap storage of a data lake with the ACID transactions, schema enforcement, and governance of a data warehouse. No need for separate lake + warehouse.
- Delta Lake β ACID transactions on data lake files
- Photon Engine β Fast SQL queries (warehouse-speed on lake data)
- Unity Catalog β Governance, security, lineage
- Serverless SQL Warehouses β On-demand compute, no cluster management
| Managed | External | |
|---|---|---|
| Data location | Databricks controls | You control (your ADLS path) |
| DROP TABLE | Deletes data + metadata | Deletes metadata ONLY, data stays |
| Use when | Most cases (simpler) | Data shared across platforms |
SECTION 6: NEW 2025-2026 FEATURES
π§ Memory Map: What's New
β‘ MUST KNOW DIRECT QUESTIONS
Databricks automatically runs OPTIMIZE and VACUUM based on table usage patterns. You don't schedule these manually anymore. Unity Catalog required.
A new feature (GA March 2026) that allows Delta tables to handle OLTP workloads (point lookups, single-row updates) β like a traditional database (PostgreSQL) but built on Delta Lake.
BEGIN ATOMIC ... END β allows changes to multiple tables in a single atomic transaction. Either ALL tables update or NONE do. New in Databricks 2025.Allows external tools (that only speak Iceberg/Hive) to read your Delta tables without conversion. Unity Catalog rewrites metadata on-the-fly.
A new data type in Delta Lake 4.x that stores semi-structured JSON data natively β no need to stringify JSON. Faster queries on nested JSON fields.
Delta Lake Advanced Masterclass -- Never Get Caught Off Guard Again
TABLE OF CONTENTS
- OPTIMIZE -- When It Helps and When It Hurts
- Liquid Clustering vs Z-ORDER vs Partitioning -- The Complete Decision Guide
- Deletion Vectors -- Internal Mechanics
- Change Data Feed (CDF) -- CDC with Delta Lake
- UniForm -- Universal Format
- Predictive Optimization
- The Small File Problem -- Root Causes and Real Solutions
- VACUUM -- Risks, Production Incidents, and Gotchas
- Delta Lake vs Apache Iceberg vs Apache Hudi
- Rapid-Fire Interview Questions with Traps
Answer First: Choose Iceberg for a multi-engine or Snowflake-heavy ecosystem, Delta for a Databricks-centered platform with deep native integration, and Hudi when record-level upserts and incremental ingestion dominate.
Memory Map: When would you choose each format? Give me the decision framework -> engine ecosystem establishes interoperability constraints -> mutation workload selects transaction semantics -> platform services determine operational fit -> cross-engine pilot verifies the format choice [DB_06_Delta_Lake_Advanced_Masterclass.md:1228].
Q23: When would you choose each format? Give me the decision framework.
Answer:
The nuanced interview answer: "In practice, the choice is often driven by ecosystem, not features. If you are on Databricks, you use Delta Lake. If you are multi-engine or Snowflake-heavy, you lean toward Iceberg. Hudi is the best choice for streaming upsert-heavy workloads but has a smaller community. The formats are converging -- Delta has UniForm for Iceberg compatibility, Iceberg added merge-on-read, and all three support ACID, time travel, and schema evolution."
Answer First: delta.enableChangeDataFeed is a table property that records change data for future commits; readChangeFeed is a reader option that requests those recorded rows. Enabling capture does not make earlier versions retroactively available.
Memory Map: the difference between "delta.enableChangeDataFeed" and "readChangeFeed" -> table property enables recording for future commits -> read option requests the recorded change stream -> enabling later cannot reconstruct earlier mutations -> history and sample reads verify the boundary [DB_06_Delta_Lake_Advanced_Masterclass.md:1313].
Q25: What is the difference between "delta.enableChangeDataFeed" and "readChangeFeed"?
Answer:
Answer First: Ordered log actions, checkpoint-assisted reconstruction, conflict checks, and atomic publication provide the transaction behavior asked about here.
Memory Map: the Delta Lake protocol -- reader and writer versions -> protocol action declares minimum reader and writer capabilities -> table features can raise those versions -> incompatible clients reject access safely -> detail output confirms negotiated requirements [DB_06_Delta_Lake_Advanced_Masterclass.md:1412].
Q29: Explain the Delta Lake protocol -- reader and writer versions.
Answer:
Answer First: Write-Audit-Publish isolates a candidate dataset, runs quality and reconciliation checks, then promotes only an approved result. With Delta, use a staging table or clone and an atomic publication step rather than nonexistent table-branch syntax.
Memory Map: Write-Audit-Publish (WAP) pattern with Delta? How do you implement it -> candidate write remains isolated from consumers -> audit queries evaluate rules and counts -> approved data receives an atomic publish step -> rejected data preserves the previous visible version [DB_06_Delta_Lake_Advanced_Masterclass.md:1506].
Q31: What is Write-Audit-Publish (WAP) pattern with Delta? How do you implement it?
Answer:
Answer First: Delta row tracking assigns stable row identifiers and records the commit version of row changes for supported workloads. It helps incremental materialization and row-level change correlation, but it is a table feature with protocol compatibility requirements.
Memory Map: Row Tracking and what is it used for -> row tracking and it used for changes row visibility through table metadata -> row-level metadata records identity or removal -> reader combines it with Parquet data -> logical state changes without immediate full rewrite -> later compaction materializes the result [DB_06_Delta_Lake_Advanced_Masterclass.md:1540].
Q32: What is Row Tracking and what is it used for?
Answer:
Answer First: Priority: HIGHEST β Delta Lake is 30-40% of any Databricks interview.
Memory Map: Type Widening and Variant types in Delta Lake -> type widening and variant types in delta lake chooses enforcement, widening, or explicit evolution -> incoming fields meet the table contract -> enforcement or explicit evolution decides compatibility -> metadata version records the shape -> downstream reader test validates change [DB_06_Delta_Lake_Advanced_Masterclass.md:1563].
Q33: What are Type Widening and Variant types in Delta Lake?
Answer (latest features):
Delta Lake β Complete Interview Guide
Memory Map
Answer First: Delta Lake is the transaction protocol and storage framework; a Delta table is one dataset made of Parquet files plus its own transaction log. The protocol gives that table atomic commits, snapshot reads, schema controls, and history.
Memory Map: The Simple Answer -> storage framework supplies transaction semantics over files -> one dataset combines Parquet data with its log directory -> readers reconstruct a snapshot from both -> operations publish later versions [Delta_01_Complete_Guide.md:32].
The Simple Answer
Real-World Analogy
Answer First: Delta Lake is the transaction protocol and storage framework; each Delta table is a concrete dataset made of Parquet data files plus its own _delta_log metadata.
Memory Map: Technical Difference β What Each Actually IS -> technology defines the protocol and implementation -> concrete dataset is an instance using that protocol -> metadata binds schema properties and files -> commands operate on the instance [Delta_01_Complete_Guide.md:64].
Technical Difference β What Each Actually IS
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β DELTA LAKE (Technology) β β β β βββββββββββββββββββ βββββββββββββββββββ β β β Delta Table: β β Delta Table: β β β β orders β β customers β β β β β β β β β β π _delta_log/ β β π _delta_log/ β β each table β β β π data.parquet β β π data.parquet β has its OWN β β β β β β transaction β β βββββββββββββββββββ βββββββββββββββββββ log β β β β Provides: ACID, Schema Enforcement, Time Travel, β β MERGE, OPTIMIZE, VACUUM, Data Skipping β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Side-by-Side Comparison
| Aspect | Delta Lake | Delta Table |
|---|---|---|
| What is it? | Open-source storage layer/framework | A single table stored in Delta format |
| Created by | Databricks (open-sourced in 2019) | You, using CREATE TABLE ... USING DELTA |
| How many? | ONE per environment (it's the technology) | MANY β you create hundreds of Delta tables |
| Contains | The protocol, the rules, the engine | Parquet data files + _delta_log/ folder |
| Analogy | The operating system (Windows) | One file on that operating system |
| Lives where? | Runs inside Spark/Databricks runtime | Stored on S3 / ADLS / GCS / DBFS |
| Version | Delta Lake 3.x (the protocol version) | Table has its own version history (0, 1, 2, 3...) |
Answer First: ) USING DELTA -- β tells Spark: "use Delta Lake format".
Memory Map: How You Create a Delta Table (using Delta Lake) -> USING DELTA selects the table provider -> schema and location establish metadata -> first commit records protocol and creation state -> catalog or path resolves the new dataset [Delta_01_Complete_Guide.md:96].
How You Create a Delta Table (using Delta Lake)
# Method 1: SQL
spark.sql("""
CREATE TABLE orders (
order_id INT,
customer STRING,
amount DOUBLE,
order_date DATE
) USING DELTA -- β tells Spark: "use Delta Lake format"
LOCATION 's3://my-bucket/orders/'
""")
# Method 2: DataFrame write
df.write.format("delta").save("s3://my-bucket/orders/")
# β
# this "delta" = use Delta Lake technology
# Method 3: In Databricks (default since DBR 8.0+)
spark.sql("CREATE TABLE orders (...)")
# β In Databricks, DELTA is the DEFAULT format
# You don't even need to say USING DELTA!
# What gets created on disk:
# s3://my-bucket/orders/
# βββ _delta_log/ β Delta Lake adds this (transaction log)
# β βββ 00000000000000000000.json β First commit: "table created with schema..."
# βββ part-00000.snappy.parquet β Actual data (still Parquet!)
# βββ part-00001.snappy.parquet β More data
Answer First: Without Delta Lake (plain Parquet): With Delta Lake (Delta Table):.
Memory Map: What Delta Lake GIVES to a Delta Table -> ordered commits add atomic mutation and recovery -> schema checks protect writes -> statistics support file pruning -> maintenance improves physical layout [Delta_01_Complete_Guide.md:149].
What Delta Lake GIVES to a Delta Table
Answer First: "Delta Lake is an open-source storage layer that sits on top of cloud storage like S3 or ADLS. It adds ACID transactions, schema enforcement, time travel, and scalable metadata handling to data lakes.
Memory Map: Interview Answers β What to Say -> concise response names open files plus transaction metadata -> mechanism explains atomic versioned commits -> tradeoff notes protocol-aware readers -> example connects the model to production [Delta_01_Complete_Guide.md:163].
Interview Answers β What to Say
"Delta Lake is an open-source storage layer that sits on top of cloud storage like S3 or ADLS. It adds ACID transactions, schema enforcement, time travel, and scalable metadata handling to data lakes. Under the hood, data is still stored as Parquet files β Delta Lake adds a transaction log that tracks every change."
"A Delta table is a specific table stored in Delta format. It's a collection of Parquet data files plus a _delta_log folder that contains the transaction history. Every Delta table has its own independent transaction log."
"Delta Lake is the technology β the protocol and engine. A Delta table is one table that uses that technology. It's like MySQL vs a table in MySQL. Delta Lake provides the ACID guarantees, and each Delta table is an individual dataset that benefits from those guarantees."
What NOT to Say:
Answer First: Delta LAKE = the L is for LAYER (it's a storage LAYER / technology).
Memory Map: Quick Memory Trick -> layer mnemonic distinguishes technology from dataset -> log-plus-files mnemonic recalls table structure -> version mnemonic recalls atomic commits -> example reinforces the distinction [Delta_01_Complete_Guide.md:191].
Quick Memory Trick
Answer First: Delta Lake adds a transaction log ( delta log/ ) on top of Parquet files. This log tracks every change β which files were added, removed, or modified. It turns a chaotic collection of files into a proper table with ACID transactions, schema enforcement, and version history.
Memory Map: Delta Lake? Why do we need it -> plain files lack coordinated mutation state -> ordered log actions define each snapshot -> optimistic checks serialize conflicting writers -> history enables audit and recovery [Delta_01_Complete_Guide.md:205].
Q01 β What is Delta Lake? Why do we need it?
Question: Your interviewer asks: "Why can't we just use Parquet files on a data lake? Why do we need Delta Lake?"
The Problem (Plain Parquet):
The Solution (Delta Lake):
Delta Lake adds a transaction log (_delta_log/) on top of Parquet files. This log tracks every change β which files were added, removed, or modified. It turns a chaotic collection of files into a proper table with ACID transactions, schema enforcement, and version history.
One-liner for interviews: "Delta Lake is an open-source storage layer that adds ACID transactions, scalable metadata handling, and time travel to existing data lakes built on Parquet."
Answer First: Delta Lake combines atomic commits, snapshot isolation, schema controls, versioned history, scalable metadata, and maintenance over Parquet data. Together these features turn a file collection into a reliable transactional table.
Memory Map: the key features of Delta Lake? (The Top 8) -> atomic commits protect concurrent changes -> enforcement and evolution govern schema -> history and change feeds expose versions -> statistics layout and cleanup sustain performance [Delta_01_Complete_Guide.md:252].
Q02 β What are the key features of Delta Lake? (The Top 8)
Question: "List the main features of Delta Lake and explain why each matters."
| # | Feature | What It Does | Why It Matters |
|---|---|---|---|
| 1 | ACID Transactions | Every write is atomic β all or nothing | No more corrupted tables from failed writes |
| 2 | Time Travel | Query any historical version of the table | Undo mistakes, audit changes, debug issues |
| 3 | Schema Enforcement | Rejects writes that don't match the table schema | Prevents bad data from entering your table |
| 4 | Schema Evolution | Automatically adds new columns when needed | Handles evolving source systems gracefully |
| 5 | MERGE (Upsert) | INSERT + UPDATE + DELETE in one atomic operation | The #1 operation for data engineering pipelines |
| 6 | Data Skipping | Skips files that can't contain query results | Makes queries 10-100x faster on large tables |
| 7 | Unified Batch + Streaming | Same table for both batch and streaming writes | No separate streaming tables needed |
| 8 | Open Format | Data stored as Parquet (open standard) | No vendor lock-in β read with Spark, Trino, Presto, etc. |
Interview Tip: Don't just list features β connect them to PROBLEMS they solve. "We needed MERGE because our booking system sends daily change feeds that contain inserts, updates, and cancellations β all in one file."
What NOT to Say: "Delta Lake is a database." β No, it's a STORAGE LAYER on top of cloud storage. The data still lives as Parquet files on ADLS/S3/GCS.
Q28 β Managed vs External Tables
Question: "What is the difference? When do you use each?"
| Aspect | Managed Table | External Table |
|---|---|---|
| Data location | Databricks-managed (auto) | YOUR storage path (you specify) |
| DROP TABLE | Deletes metadata AND data | Deletes metadata ONLY β data survives |
| Predictive Optimization | Yes (automatic) | No |
| Best for | Most tables (default) | Shared data, legacy migration |
-- Managed (recommended for new tables)
CREATE TABLE catalog.schema.orders (order_id LONG, amount DECIMAL);
-- Data stored in Databricks-managed location
-- DROP TABLE deletes everything
-- External (for data shared with other systems)
CREATE TABLE catalog.schema.legacy_orders (order_id LONG, amount DECIMAL)
LOCATION 'abfss://container@storage.dfs.core.windows.net/legacy/orders/';
-- Data stays at YOUR path even if table is dropped
Q32 β What's new in Delta Lake 4.x?
Question: "What are the latest features? Mention 2-3 to show you're up to date."
| Feature | Version | What It Does |
|---|---|---|
| Variant Data Type | 4.0 | Store semi-structured JSON without schema β query nested fields directly |
| Type Widening | 4.0 | Change column type (INT β BIGINT) without rewriting data |
| Coordinated Commits | 4.0 | Multiple engines can safely write to the same Delta table |
| UniForm | 4.0 | Auto-generate Iceberg/Hudi metadata for cross-engine reads |
| Conflict-Free DV | 4.1 | Enable Deletion Vectors without blocking concurrent writers |
| Atomic CTAS | 4.1 | CREATE TABLE AS SELECT is fully atomic (no partial tables on failure) |
| Lakebase | 2026 | Serverless PostgreSQL-compatible database inside Databricks |
Interview power move: "I'd use Liquid Clustering with Deletion Vectors enabled and CDF turned on β that gives me automatic compaction, fast updates, and incremental ETL. For cross-team sharing with Snowflake users, I'd enable UniForm so they read the same table as Iceberg."
Answer First: Run the lab as a controlled state transition: create a disposable baseline, perform one operation, inspect table history and files, then verify the expected version and rows. Reset only the isolated lab location between attempts.
Memory Map: (This section replaces YouTube videos β read + copy-paste + see the output) -> disposable baseline makes each lab repeatable -> one operation creates one observable transition -> log and table inspection connect cause to effect -> cleanup prevents shared-state contamination [Delta_01_Complete_Guide.md:1474].
(This section replaces YouTube videos β read + copy-paste + see the output)
Setup (copy-paste this first)
# βββ SETUP ββββββββββββββββββββββββββββββββββββββββββββββββ
# Create a fresh Delta table in a clean location
path = "/tmp/delta_lab/orders"
# Clean up anything from previous runs
dbutils.fs.rm(path, recurse=True) # β wipes old data (safe, /tmp only)
# Create initial data
from pyspark.sql import Row
data = [
Row(order_id=1, customer="Alice", amount=100.0),
Row(order_id=2, customer="Bob", amount=200.0),
Row(order_id=3, customer="Carol", amount=300.0),
]
df = spark.createDataFrame(data)
# Write as Delta β this creates the table AND the _delta_log
df.write.format("delta").save(path)
print("β
Delta table created at:", path)
Answer First: A new Delta table contains Parquet data files plus a _delta_log directory whose first JSON commit declares protocol, metadata, and added files. Inspect both locations to connect physical files to the committed snapshot.
Memory Map: Step 1 β Look at what Delta just created -> creation writes data files and a transaction directory -> first JSON file receives version zero -> filesystem listing reveals both components -> table query confirms the initial snapshot [Delta_01_Complete_Guide.md:1509].
Step 1 β Look at what Delta just created
# List files in the folder
files = dbutils.fs.ls(path)
for f in files:
print(f.name)
# EXPECTED OUTPUT:
# _delta_log/ β the transaction log folder
# part-00000-abc123.snappy.parquet β actual data (Parquet)
# part-00001-def456.snappy.parquet
# Now peek inside _delta_log
log_files = dbutils.fs.ls(f"{path}/_delta_log")
for f in log_files:
print(f.name)
# EXPECTED OUTPUT:
# 00000000000000000000.json β ONE commit file. This is commit #0.
Answer First: The first Delta commit is the tableβs creation record: protocol and metadata define compatibility and schema, add actions select the initial files, and commitInfo describes the write. Reading the JSON exposes those actions directly.
Memory Map: Step 2 β Read commit #0 (see the "birth certificate" of the table) -> protocol action records compatibility -> metadata action records schema and properties -> add actions identify active files -> version zero becomes the creation certificate [Delta_01_Complete_Guide.md:1531].
Step 2 β Read commit #0 (see the "birth certificate" of the table)
# Read the first commit JSON
commit_0 = spark.read.json(f"{path}/_delta_log/00000000000000000000.json")
commit_0.show(truncate=False)
# EXPECTED OUTPUT (5 rows, one per action):
# ββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
# β action β details β
# ββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ€
# β protocol β minReaderVersion=1, minWriterVersion=2 β β compat info
# β metaData β schema={order_id INT, customer STR,..} β β table schema
# β add β path=part-00000-abc.parquet, size=921 β β data file 1
# β add β path=part-00001-def.parquet, size=874 β β data file 2
# β commitInfoβ operation=WRITE, timestamp=... β β who did what
# ββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββ
Answer First: A Delta UPDATE publishes a new commit rather than editing the original commit. The new version records the row-level change through file actions while the prior snapshot remains addressable until retention removes required files.
Memory Map: Step 3 β Do an UPDATE. Watch a NEW commit appear -> update reads the current snapshot -> changed rows produce new file actions -> atomic commit publishes the next version -> history shows the recorded operation [Delta_01_Complete_Guide.md:1550].
Step 3 β Do an UPDATE. Watch a NEW commit appear.
from delta.tables import DeltaTable
dt = DeltaTable.forPath(spark, path)
# Update Alice's amount from 100 β 150
dt.update(
condition = "customer = 'Alice'",
set = {"amount": "150.0"}
)
# Now check _delta_log AGAIN
log_files = dbutils.fs.ls(f"{path}/_delta_log")
for f in log_files:
print(f.name)
# EXPECTED OUTPUT:
# 00000000000000000000.json β original commit (unchanged)
# 00000000000000000001.json β NEW commit! β¨ This is the UPDATE
Answer First: The update commit records removed or logically changed old data plus the new file state and operation metrics. Comparing commit 1 with commit 0 shows how Delta changes snapshots without mutating history.
Memory Map: Step 4 β Read commit #1. See what Delta did behind the scenes -> remove action retires replaced file state -> add action introduces rewritten rows -> operation metadata explains the mutation -> snapshot reconstruction uses the combined actions [Delta_01_Complete_Guide.md:1572].
Step 4 β Read commit #1. See what Delta did behind the scenes.
commit_1 = spark.read.json(f"{path}/_delta_log/00000000000000000001.json")
commit_1.show(truncate=False)
# EXPECTED OUTPUT:
# βββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ
# β action β details β
# βββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββ€
# β remove β path=part-00000-abc.parquet (OLD file) β β old file marked removed
# β add β path=part-00002-xyz.parquet (NEW file) β β new file with updated row
# β commitInfoβ operation=UPDATE, numUpdatedRows=1 β
# βββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββ
# π§ KEY INSIGHT:
# Delta NEVER modifies a Parquet file in place.
# It writes a NEW file with the updated row,
# and marks the OLD file as "removed" in the log.
# The old file still EXISTS on disk until VACUUM runs!
Answer First: Delta history returns committed versions with timestamps, operations, and metrics, letting operators trace state changes and choose a recovery point. It describes commits; retained data files still determine whether an old snapshot can be read.
Memory Map: Step 5 β Check the history (Delta's "audit log") -> step 5 check history delta s audit log selects the recoverable version and retained-file boundary -> known commit identifies prior state -> retained log and data reconstruct the snapshot -> read, clone, or restore applies recovery -> row reconciliation confirms result [Delta_01_Complete_Guide.md:1594].
Step 5 β Check the history (Delta's "audit log")
dt.history().select("version", "timestamp", "operation", "operationMetrics").show(truncate=False)
# EXPECTED OUTPUT:
# βββββββββ¬βββββββββββββββββββ¬ββββββββββ¬βββββββββββββββββββββββββ
# βversionβ timestamp β operationβ operationMetrics β
# βββββββββΌβββββββββββββββββββΌββββββββββΌβββββββββββββββββββββββββ€
# β 1 β 2026-04-05 10:31 β UPDATE β {numUpdatedRows: 1} β
# β 0 β 2026-04-05 10:30 β WRITE β {numOutputRows: 3} β
# βββββββββ΄βββββββββββββββββββ΄ββββββββββ΄βββββββββββββββββββββββββ
#
# Every commit = one row in DESCRIBE HISTORY. That's your audit trail.