Change Data Feed (CDF) automatically records changes (INSERT / UPDATE / DELETE) to a Delta Table and efficiently propagates "what changed" to downstream pipelines and systems. It is commonly used for incremental processing between Silver and Gold layers, and for integration with external systems.
This article walks through enabling CDF, the meaning of each _change_type value, how to read CDF data in batch and streaming modes, the foreachBatch + MERGE pattern for downstream propagation, how CDF relates to DLT APPLY CHANGES INTO, and the points the exam tends to ask about.
CDF is enabled per table. You can set it when creating a new table or by changing properties on an existing one. Only changes that occur after CDF is enabled are recorded — history from before enabling is not available.
-- 新規テーブル作成時に有効化
CREATE TABLE silver.orders (
order_id BIGINT,
customer_id BIGINT,
amount DECIMAL(10,2),
status STRING,
updated_at TIMESTAMP
)
TBLPROPERTIES (delta.enableChangeDataFeed = true);
-- 既存テーブルに対して有効化
ALTER TABLE silver.orders
SET TBLPROPERTIES (delta.enableChangeDataFeed = true);
-- ワークスペース全体でデフォルト有効化
SET spark.databricks.delta.properties.defaults.enableChangeDataFeed = true;Data read via CDF automatically includes three metadata columns. The most important one is _change_type, which indicates the kind of change.
| _change_type | Meaning | Operations that produce it |
|---|---|---|
| insert | A new row was inserted | INSERT, MERGE (NOT MATCHED THEN INSERT) |
| update_preimage | The state of the row before the update | UPDATE, MERGE (MATCHED THEN UPDATE) |
| update_postimage | The state of the row after the update | UPDATE, MERGE (MATCHED THEN UPDATE) |
| delete | The row was deleted | DELETE, MERGE (MATCHED THEN DELETE) |
For UPDATEs, both a preimage (before) and a postimage (after) row are recorded. This ability to trace exactly "what changed into what" is CDF's strength. Two additional metadata columns are also added: _commit_version (the Delta version number) and _commit_timestamp (the commit time).
-- バージョン範囲で変更を取得
SELECT * FROM table_changes('silver.orders', 5, 10);
-- タイムスタンプ範囲で変更を取得
SELECT * FROM table_changes('silver.orders', '2026-03-01', '2026-03-27');
-- 特定の_change_typeだけフィルタ
SELECT * FROM table_changes('silver.orders', 5)
WHERE _change_type IN ('insert', 'update_postimage');# バージョン指定で開始
cdf_stream = (spark.readStream
.format("delta")
.option("readChangeFeed", "true")
.option("startingVersion", 5)
.table("silver.orders")
)
# タイムスタンプ指定で開始
cdf_stream = (spark.readStream
.format("delta")
.option("readChangeFeed", "true")
.option("startingTimestamp", "2026-03-01")
.table("silver.orders")
)The most common use of CDF is incremental processing between Silver and Gold. Instead of fully rebuilding the Gold aggregate table every run, you fetch only the changes via CDF and apply them with MERGE.
def update_gold(batch_df, batch_id):
updates = batch_df.filter(
"_change_type IN ('insert', 'update_postimage')"
)
deletes = batch_df.filter("_change_type = 'delete'")
updates.createOrReplaceTempView("updates")
deletes.createOrReplaceTempView("deletes")
# UPSERT: 新規挿入と更新後の状態を反映
spark.sql("""
MERGE INTO gold.order_summary t
USING updates s ON t.order_id = s.order_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *
""")
# DELETE: 削除された行をGoldからも削除
spark.sql("""
MERGE INTO gold.order_summary t
USING deletes s ON t.order_id = s.order_id
WHEN MATCHED THEN DELETE
""")
(spark.readStream
.format("delta")
.option("readChangeFeed", "true")
.table("silver.orders")
.writeStream
.foreachBatch(update_gold)
.option("checkpointLocation", "/checkpoint/gold_orders")
.trigger(availableNow=True)
.start()
)trigger(availableNow=True) runs the stream in a batch-like fashion, processing all available CDF data and then stopping the stream automatically. It pairs well with scheduled jobs.
CDF is also useful for incremental data integration with external systems. Sending only the changes instead of resending the full dataset dramatically reduces network and processing costs.
Delta Live Tables (DLT) APPLY CHANGES INTO is conceptually similar to CDF but lives at a different layer. CDF is a change-recording feature on the Delta Table side, while APPLY CHANGES INTO is a CDC-ingestion syntax on the DLT pipeline side.
| Comparison axis | Change Data Feed | DLT APPLY CHANGES INTO |
|---|---|---|
| Role | Records and exposes changes to a Delta Table | Applies changes from a CDC source into a DLT table |
| How to enable | Table property | DLT pipeline definition (SQL/Python) |
| Key specification | Not required (every row's changes are recorded) | Primary key specified via the KEYS clause |
| Sequencing | Ordered automatically by _commit_version | Ordering column specified via the SEQUENCE BY clause |
| SCD Type 2 | User implements the logic | Managed automatically with STORED AS SCD TYPE 2 |
-- DLT APPLY CHANGES INTO の例
APPLY CHANGES INTO LIVE.silver_orders
FROM STREAM(LIVE.bronze_orders_cdc)
KEYS (order_id)
SEQUENCE BY updated_at
COLUMNS * EXCEPT (_rescued_data)
STORED AS SCD TYPE 1;CDF data is stored in the Delta Table's _change_data directory. Running VACUUM also removes CDF data that falls outside the retention window.
-- VACUUM実行(7日間保持)
VACUUM silver.orders RETAIN 168 HOURS;
-- 下流パイプラインの処理遅延を考慮して保持期間を長めに設定
ALTER TABLE silver.orders
SET TBLPROPERTIES (
'delta.deletedFileRetentionDuration' = 'interval 30 days'
);Data Engineer Professional
問題 1
CDF is enabled on the Silver orders table. A record's status is updated from 'pending' to 'shipped'. What rows will the data read from CDF contain?
正解: A
For an UPDATE operation, CDF records two rows: update_preimage (the state before) and update_postimage (the state after). This lets you fully trace what changed into what. There is no plain 'update' type, and CDF uses a preimage/postimage pair rather than a delete/insert combination.
What is the difference between CDF and Structured Streaming?
Change Data Feed (CDF) is a feature that automatically records changes to a Delta Table, exposing the results of INSERT/UPDATE/DELETE operations together with the _change_type, _commit_version, and _commit_timestamp metadata columns. Structured Streaming is Spark's streaming framework and is one of several ways to consume CDF data. Think of CDF as the mechanism that records changes, and Streaming as one way to read them.
Does enabling CDF increase storage costs?
Yes, slightly. When UPDATE or DELETE runs on a CDF-enabled table, the before/after row data is stored separately under the _change_data directory. Tables that only see INSERTs incur almost no additional cost. VACUUM can clean up old CDF data, but you must keep the retention window that downstream pipelines depend on.
How does CDF show up on the exam?
It is especially frequent on Data Engineer Professional. Common topics include how to enable CDF (table property), reading via the readChangeFeed option, the meaning of each _change_type value (insert/update_preimage/update_postimage/delete), and patterns for applying changes incrementally to downstream tables. Batch reads via the table_changes() function are also important.
Practice with certification-focused question sets
無料で問題を解いてみるNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
Databricks Certifications: All 7 Exams, Difficulty & Study Plan (2026)
Complete guide to all 7 Databricks certifications — Data Eng...
Databricks Exam Difficulty Ranking: All 7 Certs Compared (2026)
Every Databricks certification ranked by difficulty, with st...
Databricks Study Guide: Fastest Pass Route & Time Estimates (2026)
How to pass Databricks certifications efficiently. Official ...
Databricks Data Engineer Associate: Complete Guide (2026)
Domain-by-domain breakdown of the Databricks Certified Data ...
Databricks Data Engineer Professional: Complete Guide (2026)
Tactics for the Databricks Certified Data Engineer Professio...