Study guidePro
Databricks Data Engineer Professional
Every domain of the Databricks Data Engineer Professional exam, following the October 2026 exam guide, with the design trade-offs, failure modes, performance reasoning and production patterns the questions test, plus runnable SQL and PySpark and diagrams.
Aligned to the October 2026 exam guide · checked against the Databricks docs on 31 October 2026 · certlake.com/exam/data-engineer-professional/study-guide
Exam at a glance
| Questions | 60 scored, multiple choice (unscored questions may be included) |
| Time | 120 minutes |
| Pass mark | Not published; practise to 70% or better |
| Languages | Python (PySpark) and SQL; exam in English |
| Exam guide | October 2026 version, live from 9 October 2026 |
| Assumes | The Data Engineer Associate basics: Delta, Auto Loader, medallion, Jobs, Unity Catalog grants |
| Domain | Weight | ≈ Questions |
|---|---|---|
| Developing Code for Data Processing | 23% | 14 |
| Cost and Performance Optimization | 15% | 9 |
| Data Ingestion and Acquisition | 12% | 7 |
| Data Manipulation | 12% | 7 |
| Monitoring and Alerting | 10% | 6 |
| Debugging and Deploying | 10% | 6 |
| Data Security and Compliance | 8% | 5 |
| Data Governance | 5% | 3 |
| Data Modeling | 5% | 3 |
1. Developing Code for Data Processing23% of the exam
Bundle project layout
A Declarative Automation Bundle is a databricks. at the project root plus the code it deploys: resources/ for job and pipeline YAML, src/ for the package (built as a wheel), tests/ for pytest. Pull resource files in with include, so dozens of jobs and pipelines stay reviewable.
bundle:
name: orders
include:
- resources/*.yml
targets:
dev:
mode: development
default: true
prod:
mode: production
Keep secrets out of the bundle and out of Git: reference them as {{secrets/ in a Spark config or environment variable, or read them with dbutils.. databricks bundle validate checks the configuration without deploying.
Library failures by environment
| Environment | How dependencies get in | Usual failure and fix |
|---|---|---|
| Serverless notebook or job | The environment: requirements-style lines, wheels from / or / | Module after moving off classic: init scripts aren't supported, so add the wheel to the environment |
| Classic job cluster | Compute-scoped libraries (PyPI, wheel, Maven) | Version clash between jobs: give each job its own job cluster and pin versions |
| Pipeline | The pipeline's Environment settings, for all source files | Runtime installs aren't supported; declare them in the environment |
| Bundle-deployed job | artifacts builds the wheel; the task lists it under libraries (whl: .) | Wheel missing on the cluster: check the artifacts build and the libraries path |
%pip install in a notebook | Notebook-scoped only | Other tasks can't import it; install at compute or environment level |
| Private index | --index-url / --extra-index-url, or an admin's default package repository | Credentials in the URL: have an admin set the authenticated repository as the default package repository |
Also: never install PySpark (or anything that pins it) into a serverless environment; it stops the session. Serverless can run on x86_64 or aarch64, and that can change between runs, so use pure-Python wheels or ship both builds. Bump a custom package's version when it changes, because serverless caches environments.
Pick the UDF
| Need | Use |
|---|---|
| Logic a built-in function already does | The built-in: Catalyst can optimise it |
| Governed, reusable from SQL anywhere (warehouses too) | Unity Catalog function: CREATE FUNCTION … LANGUAGE SQL or LANGUAGE PYTHON; callers need EXECUTE |
| Fast Python on large data | pandas UDF (@pandas_): Arrow batches, vectorised |
| A pandas DataFrame per group, any output shape | group |
| Row-at-a-time Python, small data | @udf; register with spark. for SQL in this session only |
A Python UC function is CREATE FUNCTION f(.
Streaming table or materialized view
| Requirement | Pick |
|---|---|
| Append-only source, each row processed once, low latency | Streaming table (often with Auto Loader) |
| Result must reflect later changes to dimensions or upstream rows | Materialized view |
| Aggregates for BI, refreshed on a schedule | Materialized view (refreshes incrementally when it can) |
| Source rows get updated or deleted (CDC) | Streaming table fed by AUTO CDC |
Joins in a streaming table don't recompute when a dimension changes: rows already written keep the old attribute. Changing a streaming table's query only affects new rows until a full refresh.
AUTO CDC and SCD Type 2
CREATE OR REFRESH STREAMING TABLE customers_hist;
CREATE FLOW customers_cdc AS AUTO CDC INTO
customers_hist
FROM stream(main.cdc.customers_raw)
KEYS (customer_id)
APPLY AS DELETE WHEN op = 'DELETE'
SEQUENCE BY seq
COLUMNS * EXCEPT (op, seq)
STORED AS SCD TYPE 2;
| Clause / Python argument | Does |
|---|---|
KEYS / keys | Identifies a row |
SEQUENCE BY / sequence_ | Orders changes per key, so out-of-order events resolve correctly; no nulls; STRUCT( for ties |
APPLY AS DELETE WHEN / apply_ | Which events delete |
STORED AS SCD TYPE 1 or 2 / stored_ | Overwrite in place, or keep history with _ and _ (_ null = current) |
TRACK HISTORY ON * EXCEPT ( / track_ | SCD 2 only: changes to these columns don't open a new version |
In Python the flow is dp.. APPLY CHANGES still works with the same syntax, but AUTO CDC is the recommended name.
Declarative pipelines or plain Structured Streaming? Pick Lakeflow pipelines when you want dependencies inferred from code, managed checkpoints, retries, expectations and AUTO CDC with little operational code. Pick Structured Streaming in a job when you need full control: custom foreach logic, arbitrary sinks, or fine-grained trigger and state tuning.
Jobs control flow and automation
| Need | Build |
|---|---|
| Same task for each item in a list | For each task: nested task reads {{input}} (or {{input.); concurrency defaults to 1. A For each can't nest another For each |
| Branch on a value from an earlier task | Set it with dbutils. (key="rows", value=n), then an If/else task tests {{tasks. |
| Trigger from outside with run-specific values | Jobs API run-now with job_ (or databricks jobs run-now), then poll the run's state |
| Define the job as code | A job resource in the bundle |
Serverless settings for jobs
| Setting | Use |
|---|---|
| Standard performance mode | Cheaper (fewer DBUs, same SKU); tolerates startup latency of about 4 to 6 minutes |
| Performance optimized | Time-sensitive runs: starts and runs faster |
| Auto-optimization (on by default; may retry) | Turn it off in the task's retry policy for non-idempotent tasks that must run at most once |
| High memory (Public Preview) | Notebook tasks only: 32 GB instead of 16 GB (REPL memory, not Spark), at a higher DBU rate |
Test the code
from pyspark.testing import assertDataFrameEqual
from pyspark.testing import assertSchemaEqual
def clean(df):
return df.dropna(subset=["id"])
def test_clean(spark):
src = spark.createDataFrame(
[(1, "a"), (None, "b")], "id INT, v STRING")
out = src.transform(clean)
want = spark.createDataFrame(
[(1, "a")], "id INT, v STRING")
assertSchemaEqual(out.schema, want.schema)
assertDataFrameEqual(out, want)
Unit tests check one function on small, synthetic DataFrames. Integration tests run the connected stages end to end on sample data, for example a bundle deployed to a test target. Write each step as a function that takes and returns a DataFrame, then chain them with df..
Stateful streaming
from pyspark.sql import functions as F
counts = (spark.readStream.table("main.iot.events")
.withWatermark("event_time", "15 minutes")
.groupBy(F.window("event_time", "10 minutes"))
.count())
(counts.writeStream
.outputMode("append")
.option("checkpointLocation", chk)
.toTable("main.iot.counts_10m"))
| Output mode | Windowed aggregation writes | State |
|---|---|---|
| Append | Each window once, after the watermark passes its end | Dropped after the watermark |
| Update | Rows as they change; rewritten as data arrives | Dropped after the watermark |
| Complete | The whole result table every trigger | Never dropped: grows without bound |
- The checkpoint stores source offsets and state; with an idempotent sink such as Delta it gives exactly-once results after a restart. One checkpoint per query, never shared.
foreachis at least once. For idempotent Delta writes inside it, setBatch txnandApp Id txn(=Version batch).Id MERGEfrom a stream needsforeach.Batch - Stream-stream outer joins need watermarks; with several watermarks the default policy takes the min, so a lagging stream's data isn't dropped.
dropdrops duplicates that arrive within the watermark.Duplicates Within Watermark
The rest of this guide is part of Pro
8 more domains, explained with snippets, decision tables and diagrams:
- 2. Data Ingestion and Acquisition · 12%
- 3. Data Manipulation · 12%
- 4. Monitoring and Alerting · 10%
- 5. Cost and Performance Optimization · 15%
- 6. Data Security and Compliance · 8%
- 7. Data Governance · 5%
- 8. Debugging and Deploying · 10%
- 9. Data Modeling · 5%
Know it, or just recognise it?
The free diagnostic shows which domains you'd lose marks on, in about 10 minutes and without signing up.
Take the free diagnosticCheat sheet
The two-page cheat sheet: rules, defaults and traps for the last week before the exam.
Open the cheat sheetSpotted something out of date? Email support@certlake.com. CertLake is not affiliated with Databricks, Inc.