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

Questions60 scored, multiple choice (unscored questions may be included)
Time120 minutes
Pass markNot published; practise to 70% or better
LanguagesPython (PySpark) and SQL; exam in English
Exam guideOctober 2026 version, live from 9 October 2026
AssumesThe Data Engineer Associate basics: Delta, Auto Loader, medallion, Jobs, Unity Catalog grants
DomainWeight≈ Questions
Developing Code for Data Processing23%14
Cost and Performance Optimization15%9
Data Ingestion and Acquisition12%7
Data Manipulation12%7
Monitoring and Alerting10%6
Debugging and Deploying10%6
Data Security and Compliance8%5
Data Governance5%3
Data Modeling5%3

1. Developing Code for Data Processing23% of the exam

Bundle project layout

A Declarative Automation Bundle is a databricks.yml 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/scope/key}} in a Spark config or environment variable, or read them with dbutils.secrets.get. databricks bundle validate checks the configuration without deploying.

Library failures by environment

EnvironmentHow dependencies get inUsual failure and fix
Serverless notebook or jobThe environment: requirements-style lines, wheels from /Volumes/… or /Workspace/…ModuleNotFoundError after moving off classic: init scripts aren't supported, so add the wheel to the environment
Classic job clusterCompute-scoped libraries (PyPI, wheel, Maven)Version clash between jobs: give each job its own job cluster and pin versions
PipelineThe pipeline's Environment settings, for all source filesRuntime installs aren't supported; declare them in the environment
Bundle-deployed jobartifacts builds the wheel; the task lists it under libraries (whl: ./dist/*.whl)Wheel missing on the cluster: check the artifacts build and the libraries path
%pip install in a notebookNotebook-scoped onlyOther tasks can't import it; install at compute or environment level
Private index--index-url / --extra-index-url, or an admin's default package repositoryCredentials 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

NeedUse
Logic a built-in function already doesThe 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 datapandas UDF (@pandas_udf): Arrow batches, vectorised
A pandas DataFrame per group, any output shapegroupBy().applyInPandas(fn, schema)
Row-at-a-time Python, small data@udf; register with spark.udf.register for SQL in this session only

A Python UC function is CREATE FUNCTION f(c STRING) RETURNS STRING LANGUAGE PYTHON AS $$ … $$.

Streaming table or materialized view

RequirementPick
Append-only source, each row processed once, low latencyStreaming table (often with Auto Loader)
Result must reflect later changes to dimensions or upstream rowsMaterialized view
Aggregates for BI, refreshed on a scheduleMaterialized 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

AUTO CDC with SCD Type 2: a feed of insert, update and delete events, keyed by id and ordered by a sequence column, becomes a history table where each version has __START_AT and __END_AT, and the current version has a null __END_ATCDC feedc1 INSERT Leeds seq 1c2 INSERT Hull seq 2c1 UPDATE York seq 4c2 DELETE seq 6AUTO CDCKEYS idSEQUENCE BYSCD TYPE 2Streaming table (history)idcity__START_AT__END_ATc1Leeds14c1York4nullc2Hull26green = current version
SCD Type 2 keeps every version. SEQUENCE BY orders the changes for each key; the row with __END_AT null is current, and a delete closes the key's last version.
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 argumentDoes
KEYS / keysIdentifies a row
SEQUENCE BY / sequence_byOrders changes per key, so out-of-order events resolve correctly; no nulls; STRUCT(a, b) for ties
APPLY AS DELETE WHEN / apply_as_deletesWhich events delete
STORED AS SCD TYPE 1 or 2 / stored_as_scd_typeOverwrite in place, or keep history with __START_AT and __END_AT (__END_AT null = current)
TRACK HISTORY ON * EXCEPT (…) / track_history_except_column_listSCD 2 only: changes to these columns don't open a new version

In Python the flow is dp.create_auto_cdc_flow(target=…, source=…, keys=…, sequence_by=…). 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 foreachBatch logic, arbitrary sinks, or fine-grained trigger and state tuning.

Jobs control flow and automation

NeedBuild
Same task for each item in a listFor each task: nested task reads {{input}} (or {{input.key}}); concurrency defaults to 1. A For each can't nest another For each
Branch on a value from an earlier taskSet it with dbutils.jobs.taskValues.set() (key="rows", value=n), then an If/else task tests {{tasks.load.values.rows}} > 0
Trigger from outside with run-specific valuesJobs API run-now with job_parameters (or databricks jobs run-now), then poll the run's state
Define the job as codeA job resource in the bundle

Serverless settings for jobs

SettingUse
Standard performance modeCheaper (fewer DBUs, same SKU); tolerates startup latency of about 4 to 6 minutes
Performance optimizedTime-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.transform(clean).transform(enrich).

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 modeWindowed aggregation writesState
AppendEach window once, after the watermark passes its endDropped after the watermark
UpdateRows as they change; rewritten as data arrivesDropped after the watermark
CompleteThe whole result table every triggerNever 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.
  • foreachBatch is at least once. For idempotent Delta writes inside it, set txnAppId and txnVersion (= batchId). MERGE from a stream needs foreachBatch.
  • Stream-stream outer joins need watermarks; with several watermarks the default policy takes the min, so a lagging stream's data isn't dropped.
  • dropDuplicatesWithinWatermark drops duplicates that arrive within the 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 diagnostic

Cheat sheet

The two-page cheat sheet: rules, defaults and traps for the last week before the exam.

Open the cheat sheet

Spotted something out of date? Email support@certlake.com. CertLake is not affiliated with Databricks, Inc.