Interview track

Data Engineer interview prep

A spaced-repetition deck of 312+ Data Engineer interview questions — organised by topic and difficulty, and scheduled for review based on your ratings. Preview a few cards below, then choose access to study the whole track on an Anki-style SM-2 schedule.

312 cards15 topics
See access options

Eligible new monthly or yearly subscribers get 7 days free. Checkout confirms eligibility and charges.

Before you start

You should be able to write basic Python and SQL and understand tables and files. Spark, streaming, and architecture build on those foundations; use a small pipeline for practical exercises.

First pass: Python → Databases. Begin with the foundational questions in these modules, then follow the outline. Revisit advanced and senior questions as the job requires; all cards remain available from the start.

Shared topics can appear in several tracks and keep one review history. The outline labels shared foundations and role-specific modules; choose your depth for the job you are preparing for.

What's covered

Every topic in this track, grouped the way you'd study it.

Python

122 cards

Shared foundations

Core LanguageData Model & InternalsConcurrency & AsyncStdlib, Typing & Testing

Databases

42 cards

Shared foundations

SQL Fundamentals

Data Modeling & Warehousing

11 cards

Role-specific module

Data Modeling

ETL/ELT & Pipelines

11 cards

Role-specific module

ETL & Pipelines

Storage & File Formats

9 cards

Role-specific module

Storage & Formats

Spark & Distributed Processing

10 cards

Role-specific module

Spark

Streaming & Kafka

10 cards

Role-specific module

Streaming

SQL & Query Optimization

10 cards

Role-specific module

SQL Optimization

Data Quality & Orchestration

9 cards

Role-specific module

Data Quality

DevOps & Infra

35 cards

Shared foundations

Docker, CI/CD & Linux

Data Architecture & System Design

8 cards

Role-specific module

Architecture

Behavioral

35 cards

Shared foundations

Behavioral

Sample questions

A few cards from the deck — reveal each answer, then choose access to study the full set on a schedule.

What's the difference between mutable and immutable types?

Short answer: Mutable objects can change in place (list, dict, set); immutable objects cannot (int, str, tuple). Rebinding a variable is different from mutating its object.

items = [1, 2]
alias = items
items.append(3)
assert alias is items and alias == [1, 2, 3]

text = "hello"
original = text
text += " world"
assert original == "hello"  # the original string did not change

In depth:

  • id() identifies an object and stays constant during its lifetime. Treating it as a memory address is a CPython implementation detail.
  • A tuple cannot replace its elements, but a list stored inside it can still change. Immutability is not automatically deep immutability or thread safety.
  • Dictionary keys and set elements must be hashable: their hash stays stable, and equal objects have equal hashes. A tuple containing a list is unhashable. A user-defined mutable instance can be hashable by identity, so hashability is not synonymous with immutability.
  • Functions receive references to objects. Mutating an argument can affect the caller; rebinding a local parameter does not rebind the caller's variable.

Sources: Python hashability, object identity.

What does SELECT do, and in what order do the parts of a query execute?

Short answer: SELECT retrieves rows from tables. The logical execution order does NOT match the written order: first FROM, then WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY, LIMIT.

In depth:

Written (syntactic) order:

SELECT   DISTINCT col1, agg(col2)
FROM     t
WHERE    cond
GROUP BY col1
HAVING   agg_cond
ORDER BY col1
LIMIT    10 OFFSET 20;

Logical execution order:

1. FROM / JOIN      -- which tables, how to join
2. WHERE            -- row filter BEFORE grouping
3. GROUP BY         -- grouping
4. HAVING           -- group filter AFTER aggregation
5. SELECT           -- evaluate expressions, aliases
6. DISTINCT         -- remove duplicates
7. ORDER BY         -- sorting
8. LIMIT / OFFSET   -- slice

⚠️ Gotcha: an alias from SELECT cannot be used in WHERE (since WHERE runs before SELECT), but it can be used in ORDER BY and often in GROUP BY (depends on the DBMS). Example of the error:

SELECT salary * 12 AS annual FROM emp WHERE annual > 100000; -- ERROR
SELECT salary * 12 AS annual FROM emp ORDER BY annual;        -- OK

How does OLTP differ from OLAP, and why don't you run analytics on the production OLTP database?

Short answer: OLTP serves short transactions — inserting and updating individual rows with low latency, while OLAP answers analytical queries that scan millions of rows. Row storage is common for OLTP and columnar storage for OLAP; these are workload categories, not mandatory storage layouts. You don't run heavy analytics on the production OLTP database because it competes for resources with transactions and tanks production latency.

In depth:

  1. Workload profile — OLTP: many small operations (INSERT/UPDATE by primary key); OLAP: few heavy queries with GROUP BY and aggregations.
  2. Storage model — row storage reads the whole row (good for transactions); columnar reads only the needed columns and compresses better (good for analytics).
  3. Normalization — OLTP often uses normalization for write integrity; OLAP often uses dimensional or denormalized models for analysis. Hybrid designs exist.
  4. Resource isolation — an analytical scan floods the buffer cache and disk, so transactions start to wait.
Criterion OLTP OLAP
Purpose transactions analytics
Operations row reads/writes column aggregations
Typical storage row-wise columnar
Common model normalized dimensional/star
Metric latency, TPS scan throughput

⚠️ Common mistake: running reports directly against the production database. Extract data into a separate warehouse (ETL/ELT) so analytics doesn't disturb transactions.

What is the difference between ETL and ELT, why did ELT win with cloud warehouses, and when does ETL still make sense?

Short answer: ETL transforms data before loading (on a separate engine), while ELT first loads raw data into the warehouse and runs transformations inside it in SQL. ELT became the default because cloud MPP warehouses (Snowflake, BigQuery, Redshift) scale compute cheaply and separate storage from compute.

In depth:

  1. ETL — transform on an intermediate engine (historically pricey ETL servers). Only clean, ready data lands in the warehouse. Downside: logic is locked in the tool and the raw data is lost.
  2. ELT — load the raw layer as-is, transform via dbt/SQL. Upside: raw is preserved, transformations are version-controlled in Git, and the warehouse handles scaling.
  3. Why ELT won — separating storage/compute made in-warehouse compute cheap and elastic; analysts prefer keeping logic in SQL.
Criterion ETL ELT
Where transform runs On a separate engine Inside the warehouse
Raw layer Usually lost Preserved
Scaling Bound by the engine Elastic (MPP)
Typical stack Informatica, SSIS Fivetran + dbt + Snowflake

When ETL still fits: heavy preprocessing before the warehouse, masking PII/compliance (raw cannot be loaded), or a source easier to coerce to schema on the fly.

⚠️ Common mistake: thinking ELT means "no transformations." The transformations didn't disappear — they just moved into the warehouse and run after loading.

How does columnar storage differ from row storage, and why is columnar faster and cheaper for analytics?

Short answer: In a row format the values of a single record sit together; in a columnar format all values of one column sit together. Analytical queries (aggregates over a few of dozens of columns) read only the needed columns, compress far better and support predicate pushdown — so less I/O and lower cost.

In depth:

  1. Column projection (projection pushdown) — a query needs 3 of 50 columns, and a columnar engine reads only those three off disk. A row format must read the whole row.
  2. Compression — a column holds homogeneous values (one type, similar data), so dictionary, run-length and delta encoding reach compression ratios several times higher than on a heterogeneous row.
  3. Predicate pushdown — using stored per-block min/max statistics, a filter like WHERE date = ... skips whole blocks without reading them.
  4. Row format wins for point operations: read/write a whole record (OLTP, one-record-at-a-time streaming).
Row layout:   [id=1,name=A,ts=..][id=2,name=B,ts=..][id=3,...]
               └── record 1 ──┘└── record 2 ──┘

Columnar layout:
  id:   [1, 2, 3, ...]        ← read only the columns
  name: [A, B, C, ...]          you need, each one
  ts:   [.., .., .., ...]       compressed separately

⚠️ Common mistake: treating columnar as universally better. For row-at-a-time writes and whole-record reads (streaming, transactional updates) a row format (Avro) is more efficient.

Describe Spark's architecture: driver, executors, cluster manager. How is a job broken into jobs, stages, and tasks?

Short answer: The driver builds the plan and coordinates execution, the cluster manager (YARN, Kubernetes, Standalone) allocates resources, and executors on the workers run tasks and hold data in memory. Every action launches a job, which the scheduler cuts into stages at shuffle boundaries, and each stage into tasks by partition count.

In depth:

  1. Driver — the process running your code and the SparkSession. It builds the logical and physical plan, the DAG of stages, schedules tasks, and collects results. If the driver dies, the whole application dies.
  2. Cluster manager — negotiates resources: how many executors, how many cores and how much memory each. It does no computation itself.
  3. Executors — JVM processes on the workers. They run tasks, cache partitions, and serve data during shuffles. They live for the application's lifetime.
  4. Work hierarchy — Job (one per action) → Stage (bounded by shuffles) → Task (one per partition, the smallest unit of parallelism).
            ┌──────────────┐
            │    Driver    │  plan + DAG + scheduler
            │ SparkSession │
            └──────┬───────┘
                   │ request resources
            ┌──────▼───────┐
            │Cluster Manager│  YARN / K8s / Standalone
            └──────┬───────┘
        ┌──────────┼──────────┐
   ┌────▼────┐ ┌───▼────┐ ┌───▼────┐
   │ Executor│ │Executor│ │Executor│  tasks + cache
   └─────────┘ └────────┘ └────────┘

⚠️ Common mistake: conflating executor cores with tasks — parallelism is capped at num executors × cores, and if there are fewer partitions than slots, some cores sit idle.

Ready to make it stick?

Explore a sample, choose a track, and build a review routine that fits your preparation.

Questions about this track

How should I prepare for a Data Engineer interview?

Study the concepts you'll be asked to explain, not just the ones you can code. RecallDeck's Data Engineer track gives you 312+ curated interview questions and resurfaces each one with an Anki-style SM-2 schedule based on your ratings — to practise recalling and explaining them. Combine reviews with coding and mock interviews.

What topics does the Data Engineer track cover?

The Data Engineer track is organised into the core areas Data Engineer interviews actually test, grouped by topic and by difficulty (Concept, Junior, Middle, Senior). You can preview the full outline and sample questions above before signing in.

Is spaced repetition effective for Data Engineer interview prep?

Yes. Active recall and spaced practice can help retain what you study. Grade yourself honestly and check your understanding with practical work. RecallDeck schedules each Data Engineer card using your ratings, so familiar cards return less often and difficult ones get more practice.

Can I try the Data Engineer track before paying?

Eligible new monthly or yearly subscribers can try the complete Data Engineer track and every feature for seven days. Checkout confirms trial eligibility and the amount due; returning subscribers may be charged immediately. Cancel online before the trial ends to avoid its first charge. Lifetime access has no trial.

Other interview tracks