This page requires JavaScript to display.
Q
Unpacking...
← Interview Prep
Interview Prep

DE Interview Questions

197 commonly asked data engineering interview questions with concise model answers, covering SQL, modeling, Spark and Databricks, streaming, AWS, governance, pipeline design and behavioral rounds.

Contents
1. SQL 2. SQL: NULL Traps 3. Data Modeling & Warehousing 4. Spark & Databricks 5. Databricks Platform 6. Delta Lake Deep Dive 7. Hadoop, HDFS & Hive 8. Streaming: Kafka & Kinesis 9. AWS & Data Lakes 10. AWS: S3, IAM & Security 11. AWS: Glue, EMR & Athena 12. AWS: Redshift, Lambda & Orchestration 13. AWS: Migration, Governance & Streaming 14. AWS: Monitoring, Cost & Scenarios 15. Governance & Compliance 16. Pipelines, Incremental Load & Orchestration 17. Python for Data Engineers 18. Scenario & System Design 19. Role-Specific Prep 20. Behavioral Questions

1. SQL

SQL is tested in nearly every DE loop, usually live. Expect window functions, joins, dedup and gaps-and-islands. For the full set of tricky questions, see the SQL Interview Questions page.

Q1.What is the difference between ROW_NUMBER, RANK and DENSE_RANK?
All three number rows within a window. ROW_NUMBER is always unique (1,2,3,4). RANK gives ties the same number and leaves gaps (1,2,2,4). DENSE_RANK gives ties the same number with no gaps (1,2,2,3). Use DENSE_RANK for "Nth highest salary" questions.
Q2.How do you remove duplicate rows, keeping the latest version of each key?
Number the rows per key ordered by the change timestamp and keep row 1:
WITH ranked AS (
  SELECT *,
         ROW_NUMBER() OVER (PARTITION BY customer_id
                            ORDER BY updated_at DESC) AS rn
  FROM customers_raw
)
SELECT * FROM ranked WHERE rn = 1;
Q3.Find the second-highest salary in each department.
SELECT dept_id, salary
FROM (
  SELECT dept_id, salary,
         DENSE_RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rnk
  FROM employees
) t
WHERE rnk = 2;
Q4.WHERE vs HAVING?
WHERE filters rows before grouping; HAVING filters groups after aggregation, so it can reference aggregates like COUNT(*) > 5. Push filters into WHERE whenever possible so less data reaches the aggregation.
Q5.Explain INNER, LEFT, FULL OUTER, CROSS and SELF joins. What happens with NULL join keys?
INNER keeps matches only; LEFT keeps every left row (NULLs where no match); FULL OUTER keeps unmatched rows from both sides; CROSS is the Cartesian product; a SELF join joins a table to itself (e.g. employee → manager). NULL never equals NULL, so rows with NULL keys never match in an equi-join. Also watch for duplicate keys on the right side, which silently multiply rows.
Q6.How would you compute a running total and a 7-day moving average?
SELECT order_date, revenue,
       SUM(revenue) OVER (ORDER BY order_date) AS running_total,
       AVG(revenue) OVER (ORDER BY order_date
                          ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS ma_7d
FROM daily_revenue;
Q7.What is the gaps-and-islands problem? Find users with 3+ consecutive login days.
Subtracting a row number from the date gives a constant for each consecutive streak, so you can group on it:
WITH d AS (
  SELECT DISTINCT user_id, login_date FROM logins
), g AS (
  SELECT user_id, login_date,
         login_date - ROW_NUMBER() OVER (PARTITION BY user_id
                                         ORDER BY login_date) * INTERVAL '1 day' AS grp
  FROM d
)
SELECT user_id, MIN(login_date) AS start_day, COUNT(*) AS streak
FROM g GROUP BY user_id, grp
HAVING COUNT(*) >= 3;
Q8.UNION vs UNION ALL? DELETE vs TRUNCATE vs DROP?
UNION deduplicates (sort/hash cost); UNION ALL just appends and is faster. DELETE removes rows (can filter, is logged, can be rolled back); TRUNCATE removes all rows quickly without row-level logging; DROP removes the table and its definition.
Q9.Why does NOT IN return no rows when the subquery contains a NULL? What should you use instead?
x NOT IN (a, b, NULL) expands to x <> a AND x <> b AND x <> NULL; the last comparison is UNKNOWN, so no row passes. Use NOT EXISTS or a LEFT JOIN … IS NULL anti join:
-- employees who manage nobody (manager_id contains NULL for the CEO)
SELECT * FROM employees e
WHERE NOT EXISTS (SELECT 1 FROM employees r WHERE r.manager_id = e.employee_id);
Q10.COUNT(*) vs COUNT(column) after a LEFT JOIN?
COUNT(*) counts rows, so an empty department still shows 1 (the row of NULLs). COUNT(e.employee_id) skips NULLs and correctly shows 0.
Q11.Find employees who earn more than their manager.
SELECT e.first_name, e.salary, m.first_name AS manager, m.salary AS manager_salary
FROM employees e
JOIN employees m ON m.employee_id = e.manager_id
WHERE e.salary > m.salary;
Use a LEFT JOIN instead when you need to keep the CEO, who has no manager.
Q12.What is a non-equi join? Give an example.
A join on a condition other than equality, such as a range:
SELECT e.*
FROM employees e
JOIN jobs j ON j.job_id = e.job_id
WHERE e.salary NOT BETWEEN j.min_salary AND j.max_salary;
Q13.Print an org chart with each employee's level and reporting path.
Use a recursive CTE: an anchor row (the root) unioned with a step that joins back to the CTE:
WITH RECURSIVE org(employee_id, lvl, path) AS (
  SELECT employee_id, 1, first_name FROM employees WHERE manager_id IS NULL
  UNION ALL
  SELECT e.employee_id, o.lvl + 1, o.path || ' > ' || e.first_name
  FROM employees e JOIN org o ON e.manager_id = o.employee_id
)
SELECT * FROM org ORDER BY path;
Q14.Compute the median salary per department without a MEDIAN function.
SELECT department_id, AVG(salary) AS median_salary
FROM (
  SELECT department_id, salary,
         ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary) AS rn,
         COUNT(*)     OVER (PARTITION BY department_id)                 AS cnt
  FROM employees
) t
WHERE rn IN ((cnt + 1) / 2, (cnt + 2) / 2)
GROUP BY department_id;
With integer division this picks the middle row for odd counts and the two middle rows for even counts.

2. SQL: NULL Traps

NULL means "unknown", and SQL uses three-valued logic: a comparison with NULL is neither TRUE nor FALSE but UNKNOWN, and WHERE keeps only TRUE rows. Almost every NULL trick question comes back to that rule.

Q1.What does SELECT NULL = NULL return? Why does WHERE col = NULL return no rows?
It returns NULL (UNKNOWN), not TRUE, because two unknown values cannot be known to be equal. WHERE drops UNKNOWN rows, so WHERE col = NULL never matches. Use IS NULL / IS NOT NULL, or the null-safe a IS NOT DISTINCT FROM b (Postgres, Spark SQL, Snowflake; a <=> b in MySQL and Spark).
Q2.Evaluate: NULL AND FALSE, NULL AND TRUE, NULL OR TRUE, NULL OR FALSE, NOT NULL.
FALSE, NULL, TRUE, NULL, NULL. If the known operand decides the result on its own (FALSE for AND, TRUE for OR), the answer is known; otherwise it stays UNKNOWN. That is why rewriting a filter with NOT does not bring NULL rows back.
Q3.A table has status values 'A', 'B' and NULL. How many rows does WHERE status <> 'A' return?
Only the 'B' rows. NULL <> 'A' is UNKNOWN, so NULL rows are silently excluded, a very common reporting bug. Use WHERE status IS DISTINCT FROM 'A' or WHERE status <> 'A' OR status IS NULL. The same applies to NOT (amount > 100): it does not return NULL amounts.
Q4.Table t(x) holds 1, 2 and NULL. What do COUNT(*), COUNT(x), SUM(x), AVG(x) and MIN(x) return?
3, 2, 3, 1.5 and 1. Aggregate functions skip NULLs; only COUNT(*) counts rows. So AVG(x) is 3/2 = 1.5, not 3/3 = 1. If NULL should mean zero, write AVG(COALESCE(x, 0)), which returns 1.
Q5.What does SUM return when every value is NULL, or the table is empty?
NULL, not 0 (COUNT returns 0). This breaks totals and downstream arithmetic, e.g. revenue - refunds becomes NULL when there were no refunds. Wrap it: COALESCE(SUM(amount), 0).
Q6.A row has col NULL. Does WHERE col NOT IN (1, 2) return it? Does WHERE col IN (1, NULL) match when col = 3?
No to both. NULL NOT IN (1, 2) is UNKNOWN, so the row is excluded. 3 IN (1, NULL) expands to 3 = 1 OR 3 = NULL = FALSE OR UNKNOWN = UNKNOWN, so no match (though 1 IN (1, NULL) is TRUE). Compare the classic trap in the SQL section, where a NULL inside a NOT IN subquery returns zero rows.
Q7.Why does this LEFT JOIN behave like an INNER JOIN?
SELECT c.customer_id, o.order_id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
WHERE o.status = 'SHIPPED';
Customers without orders get NULL in every o column, and NULL = 'SHIPPED' is UNKNOWN, so the WHERE clause removes exactly the rows the LEFT JOIN was meant to keep. Move the condition into the join: LEFT JOIN orders o ON o.customer_id = c.customer_id AND o.status = 'SHIPPED'. The exception is WHERE o.order_id IS NULL, which is the deliberate anti-join pattern.
Q8.Two tables both have NULL in the join key. Do those rows join?
No. NULL = NULL is UNKNOWN, so NULL keys never match in an equi-join (and are dropped by INNER joins). If NULLs should match, use a null-safe join: ON a.k IS NOT DISTINCT FROM b.k or a.k <=> b.k. Avoid COALESCE(k, -1) sentinels unless -1 can never be a real value; they also block index use.
Q9.How are NULLs treated by GROUP BY, DISTINCT, UNION, INTERSECT and EXCEPT?
As equal to each other, unlike in comparisons and joins. All NULLs form one group, DISTINCT keeps a single NULL, and set operators treat NULL rows as duplicates (UNION removes them, INTERSECT matches them). So SELECT COUNT(DISTINCT x) ignores NULLs, but SELECT DISTINCT x returns one NULL row.
Q10.Does a UNIQUE constraint allow multiple NULLs? Does CHECK (amount > 0) reject a NULL amount?
UNIQUE: in most databases (Postgres, Oracle, MySQL, SQLite) multiple NULLs are allowed because NULLs are not equal to each other. SQL Server allows only one (use a filtered unique index), and Postgres 15+ offers UNIQUE NULLS NOT DISTINCT. CHECK: no, it accepts NULL, because a CHECK fails only when the result is FALSE, and UNKNOWN passes. Add NOT NULL if the value is required.
Q11.Where do NULLs appear in ORDER BY?
It depends on the database. With ascending order, Postgres and Oracle put NULLs last (treated as larger than any value), while MySQL, SQL Server, SQLite and Spark put them first. Be explicit with ORDER BY amount DESC NULLS LAST; in MySQL or SQL Server emulate it with ORDER BY amount IS NULL, amount or a CASE expression. This matters for "top N" and ROW_NUMBER queries.
Q12.Why does this CASE never return 'missing'?
SELECT CASE region WHEN NULL THEN 'missing' ELSE region END FROM sales;
A simple CASE compares with =, so region = NULL is never TRUE. Use a searched CASE: CASE WHEN region IS NULL THEN 'missing' ELSE region END, or just COALESCE(region, 'missing').
Q13.What do 5 + NULL and 'abc' || NULL return? Does CONCAT behave the same?
Arithmetic with NULL gives NULL, and so does standard || concatenation. CONCAT varies: SQL Server and Postgres CONCAT treat NULL as an empty string, but MySQL and Spark CONCAT return NULL if any argument is NULL. CONCAT_WS skips NULLs in MySQL, Postgres and Spark. Oracle is the odd one: it treats an empty string as NULL, and its || ignores NULLs.
Q14.COALESCE vs ISNULL / NVL / IFNULL? How do you avoid divide-by-zero with NULLIF?
COALESCE(a, b, c) is standard, takes any number of arguments and returns the first non-NULL. ISNULL (SQL Server), NVL (Oracle) and IFNULL (MySQL, SQLite) take two. Gotcha: SQL Server's ISNULL returns the first argument's type, so a longer replacement string can be truncated. NULLIF(a, b) returns NULL when a = b, so revenue / NULLIF(orders, 0) gives NULL instead of an error when orders is 0.
Q15.How do you forward-fill NULLs with the last known value?
Use LAST_VALUE … IGNORE NULLS over a running window (Oracle, Snowflake, BigQuery, Spark SQL):
SELECT ts, device_id,
       LAST_VALUE(reading IGNORE NULLS) OVER (
         PARTITION BY device_id ORDER BY ts
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS reading_filled
FROM sensor_readings;
Postgres lacks IGNORE NULLS: build a group number with COUNT(reading) OVER (PARTITION BY device_id ORDER BY ts) (it only increments on non-NULL rows), then take MAX(reading) over each group. Also note LAG/LEAD return NULL at the edges unless you pass a default: LAG(amount, 1, 0).
Q16.How do you count NULLs in each column of a table?
SELECT COUNT(*)                                  AS total_rows,
       COUNT(*) - COUNT(email)                   AS null_emails,
       SUM(CASE WHEN phone IS NULL THEN 1 ELSE 0 END) AS null_phones
FROM customers;
A standard data-profiling query, and a building block for data-quality completeness checks.

3. Data Modeling & Warehousing

Interviewers want to hear you reason about grain, keys and history, not just recite definitions.

Q1.OLTP vs OLAP?
OLTP systems serve many small, concurrent reads and writes on normalized, row-oriented tables (orders app). OLAP systems serve large scans and aggregations over denormalized, usually columnar storage (warehouse). OLTP optimizes for write integrity; OLAP for read throughput.
Q2.Star schema vs snowflake schema?
A star schema has one fact table joined directly to denormalized dimensions: fewer joins, simpler queries. A snowflake schema normalizes dimensions into sub-dimensions: less redundancy, more joins. Most analytic warehouses favor star schemas because storage is cheap and joins are not.
Q3.What is the grain of a fact table and why declare it first?
The grain is exactly what one row represents, e.g. "one line item per order". Declaring it first decides which dimensions can attach and which measures are additive. Mixing grains in one fact table causes double counting.
Q4.Explain SCD Type 1, 2 and 3.
Type 1 overwrites the old value (no history). Type 2 inserts a new row per change with effective_from, effective_to and is_current, keeping full history under a new surrogate key. Type 3 keeps a "previous value" column, so only limited history. Type 2 is the one most often asked to implement.
Q5.Additive, semi-additive and non-additive facts?
Additive facts (sales amount) sum across every dimension. Semi-additive facts (account balance) sum across some dimensions but not time. Non-additive facts (ratios, percentages) cannot be summed; store their components and compute the ratio at query time.
Q6.Surrogate key vs natural key?
A natural key comes from the source (email, SKU). A surrogate key is a warehouse-generated integer or hash with no business meaning. Surrogates insulate the warehouse from source key changes, make SCD Type 2 possible, and join faster.
Q7.ETL vs ELT?
ETL transforms before loading, typically on a separate engine. ELT loads raw data first and transforms inside the warehouse or lakehouse (dbt, Spark SQL), which keeps raw history and uses the warehouse's scalable compute. Modern cloud stacks lean ELT.
Q8.Where do you use 1NF, 2NF and 3NF in a data platform?
3NF is the usual target for OLTP sources and Inmon-style integration layers. Bronze is raw and not normalised; silver is at least 1NF (arrays exploded, JSON flattened) with 3NF-like entities; gold marts are deliberately denormalised star schemas. 2NF only matters with composite keys.
Q9.What is a high-cardinality column, and how does it affect partitioning?
A column with many distinct values relative to row count (txn_id, email). Never partition on it, since that creates millions of tiny files. Partition on a low-to-medium cardinality filter column such as date, and use clustering or Z-order for high-cardinality filter columns.
Q10.How do you implement SCD Type 2 in Spark on a table with no partitions?
Deduplicate the source to one row per key and add a NULL-safe hash of tracked columns (sha2(to_json(struct(...)))). With Delta, run one MERGE whose source is a union: every row keyed by business key (closes the current row if the hash changed) plus changed rows again with a NULL key (never matches, so it is inserted as the new version). It is atomic and idempotent. Without Delta, rebuild the dimension with a full outer join, write to a new location and swap.

4. Spark & Databricks

Expect questions on the execution model, shuffles, skew and tuning.

Q1.Transformations vs actions, and what is lazy evaluation?
Transformations (select, filter, join) build a logical plan without running anything. Actions (count, collect, write) trigger execution. Laziness lets the Catalyst optimizer see the whole plan and push filters down, prune columns and reorder work.
Q2.Narrow vs wide transformations?
Narrow transformations (map, filter) compute each output partition from one input partition, with no data movement. Wide ones (groupBy, join, distinct) need a shuffle across the network and create a new stage boundary.
Q3.Explain jobs, stages and tasks.
Each action creates a job. The DAG scheduler splits the job into stages at shuffle boundaries. Each stage runs one task per partition on executors. Count of tasks ≈ number of partitions.
Q4.repartition vs coalesce?
repartition(n) does a full shuffle and can increase or decrease partitions, producing even sizes. coalesce(n) only merges existing partitions without a full shuffle, so it is cheap but can only reduce the count and may leave partitions uneven.
Q5.What is data skew and how do you fix it?
Skew is when a few keys hold most of the data, so a few tasks run far longer than the rest. Fixes: enable Adaptive Query Execution skew-join handling, broadcast the small side, salt the hot key (append a random suffix and replicate the other side), or filter/handle null and hot keys separately.
Q6.When does Spark use a broadcast join?
When one side is smaller than spark.sql.autoBroadcastJoinThreshold (10 MB by default) or you add a broadcast() hint. The small table is copied to every executor so the large side does not shuffle.
Q7.cache vs persist?
cache() is persist() with the default storage level (MEMORY_AND_DISK for DataFrames). persist lets you choose the level. Cache only data reused by multiple actions, and unpersist when done.
Q8.What is Delta Lake and what problems does it solve?
Delta adds a transaction log on top of Parquet, giving ACID writes, MERGE upserts, schema enforcement and evolution, time travel, and OPTIMIZE/Z-ORDER for small-file compaction and data skipping.
Q9.How would you size a Spark cluster to process 1 TB?
1 TB / 128 MB ≈ 8,000 tasks. Use ~5-core executors with ~7 GB per core for joins; on r5d.4xlarge (16 vCPU, 128 GB) that is 3 executors per node. Ten workers give 150 cores, about 53 waves, roughly 45–60 minutes. Set shuffle partitions ≈ 8,000, enable AQE and skew join, use Kryo, and keep local NVMe for shuffle spill. You do not need 1 TB of RAM; Spark spills.
Q10.How do you decide how many cores you need?
cores ≈ tasks × avg seconds per task / target seconds. Measure task time from a sample in the Spark UI. Cores beyond the task count sit idle; aim for 2–4 tasks per core. Kafka partitions and unsplittable files also cap parallelism.
Q11.How do you migrate a pandas batch job to Databricks?
If it is small and fast, run it as-is on a single-node cluster. Otherwise use the pandas API on Spark for a quick port, or rewrite with the DataFrame API for performance: replace row loops and apply() with built-in and window functions, broadcast small lookups, write Delta tables, and reconcile outputs against the old job.
Q12.%run vs dbutils.notebook.run?
%run executes another notebook inline and shares its variables, which is useful for including shared code. dbutils.notebook.run launches a separate run with parameters and a timeout, and returns only a string, which is useful for branching and parallel workflows.
Q13.Can you run PyFlink on Databricks?
Not in a supported way; it would only run a local mini-cluster on the driver. Use Structured Streaming (with withWatermark, transformWithState) for second-level latency, and run Flink on a managed service when millisecond latency is required, sharing data through Kafka and Delta/Iceberg.

5. Databricks Platform

Platform questions come up for any Databricks-heavy role: ingestion, layout, deployment and environments.

Q1.What is Auto Loader and how does it guarantee exactly-once ingestion?
A Structured Streaming source (cloudFiles) that ingests only new files from cloud storage into Delta. Processed files are tracked in the checkpoint (RocksDB) and committed together with the Delta write, so each file is loaded exactly once. It infers and evolves schema (schemaLocation, _rescued_data) and discovers files by directory listing or cloud notifications. Run it with trigger(availableNow=True) for scheduled incremental batches.
Q2.Auto Loader vs COPY INTO?
Both are idempotent incremental loaders. COPY INTO is a simple SQL command, fine for thousands of files. Auto Loader is a streaming source that scales to millions of files, supports file notifications, and handles schema evolution and rescued data. Auto Loader is the default choice for production bronze ingestion.
Q3.What is liquid clustering and when would you use it instead of partitioning?
A Delta layout feature that incrementally co-locates rows by up to 4 clustering keys, so file statistics skip most files. Unlike partitioning it works with high-cardinality columns, avoids small files and skew, and keys can be changed with ALTER TABLE … CLUSTER BY without a rewrite. It is opt-in per table and runs during OPTIMIZE (or predictive optimisation). Use it for most new tables; it cannot be combined with partitioning or Z-ORDER.
Q4.Lakeflow Declarative Pipelines vs hand-written Spark jobs?
Declarative pipelines (formerly DLT) suit standard medallion flows: you declare streaming tables and materialized views, and get expectations (data-quality rules), AUTO CDC for SCD1/2, lineage and orchestration for free. Custom Spark jobs suit complex stateful logic, special sinks, fine-grained tuning, or a need to stay portable to open-source Spark.
Q5.How do you deploy and schedule Databricks jobs in production?
Define jobs as code in an Asset Bundle (databricks.yml + resources), with targets per environment, mode: production and run_as a service principal. CI/CD runs tests and then databricks bundle deploy -t prod. The schedule (Quartz cron with a timezone), retries, timeouts, notifications and health rules live in the job YAML; the Lakeflow Jobs scheduler starts runs on job compute. No manual UI edits in prod.
Q6.How do you separate dev, test, preprod and prod on Databricks?
By workspace, catalog and identity, not by cluster: a workspace per environment (ideally separate cloud accounts) sharing a regional Unity Catalog metastore, with catalogs like dev_fraud and prod_fraud bound to their workspace. Cluster policies differ per environment, only service principals deploy to and run in prod, lower environments use masked or synthetic data (preprod can use clones of prod with PII masked), and one bundle is promoted with only variables changing.
Q7.Deep clone vs shallow clone?
A deep clone copies data files and metadata into an independent table, suitable for preprod copies, backups or DR. A shallow clone copies only metadata and points at the source files, so it is instant and cheap for tests but depends on the source files remaining (VACUUM on the source can break it).
Q8.What does a production Databricks setup look like for a bank?
Separate workspaces per environment in separate cloud accounts in-country, a customer-managed VPC with PrivateLink and no public IPs, SSO + SCIM with group-based access and service principals, Unity Catalog with catalog-per-environment-and-domain and workspace binding, customer-managed KMS keys, cluster policies with job-only compute in prod, audit logs to the SIEM, everything in Terraform and Asset Bundles, and CI/CD with approvals.
Q9.What is Unity Catalog? Managed vs external tables?
Databricks' governance layer: a three-level namespace (catalog.schema.table), grants, row filters and column masks, automatic lineage, audit logs, tags, and governance of volumes, models and functions, plus Delta Sharing. For managed tables UC owns the files and dropping the table deletes data; for external tables the files stay in your storage path.
Q10.How would you create a lakehouse in Databricks?
Short answer to open with: "I would put Unity Catalog in front of cloud storage, ingest raw data incrementally into bronze Delta tables, clean and merge it into silver, model gold tables for consumers, orchestrate it as Lakeflow jobs deployed through Asset Bundles, and govern access with Unity Catalog grants, masks and lineage." Then walk through the steps below, adapting them to the requirements (sources, latency, data volume, regulations).
 cloud storage (S3 / ADLS / GCS)
   └─ Unity Catalog: storage credential → external location → catalog → schemas → tables / volumes
 sources ──► INGEST (Auto Loader, Kafka streaming, Lakeflow Connect)
   ──► BRONZE (raw, append-only Delta) ──► SILVER (clean, deduplicated, merged) ──► GOLD (marts, aggregates)
   ──► SERVE: SQL warehouses, dashboards, BI tools, ML, Delta Sharing
 cross-cutting: Lakeflow Jobs / Declarative Pipelines · Asset Bundles + CI/CD · grants, masks, lineage · monitoring
1. Set up storage and Unity Catalog
Use a Unity Catalog-enabled workspace. Create a cloud bucket/container with encryption and no public access, give Databricks access through a storage credential (an IAM role on AWS, an access connector managed identity on Azure), and register external locations. Then create a catalog per environment (and often per domain) with bronze, silver and gold schemas.
CREATE EXTERNAL LOCATION IF NOT EXISTS raw_landing
  URL 's3://acme-lake-prod/landing'
  WITH (STORAGE CREDENTIAL acme_lake_cred);

CREATE CATALOG IF NOT EXISTS fraud_prod
  MANAGED LOCATION 's3://acme-lake-prod/managed/fraud_prod';

CREATE SCHEMA IF NOT EXISTS fraud_prod.bronze;
CREATE SCHEMA IF NOT EXISTS fraud_prod.silver;
CREATE SCHEMA IF NOT EXISTS fraud_prod.gold;
CREATE VOLUME IF NOT EXISTS fraud_prod.bronze.checkpoints;     -- streaming checkpoints and files
2. Bronze: ingest raw data incrementally
Land data as received, append-only, with lineage columns, so bronze is the replay point. Use Auto Loader for files, Structured Streaming for Kafka/Kinesis/Event Hubs, and Lakeflow Connect for databases and SaaS sources.
from pyspark.sql import functions as F

(spark.readStream.format("cloudFiles")
    .option("cloudFiles.format", "json")
    .option("cloudFiles.schemaLocation", "/Volumes/fraud_prod/bronze/checkpoints/txn_schema")
    .load("s3://acme-lake-prod/landing/transactions/")
    .select("*",
            F.col("_metadata.file_path").alias("source_file"),
            F.current_timestamp().alias("ingested_at"))
    .writeStream
    .option("checkpointLocation", "/Volumes/fraud_prod/bronze/checkpoints/txn")
    .trigger(availableNow=True)                    # incremental batch: process new files, then stop
    .toTable("fraud_prod.bronze.transactions"))
3. Silver: clean, validate, deduplicate and merge
Cast types, apply data-quality rules (quarantine bad rows instead of dropping them silently), deduplicate, tokenise PII, and MERGE into silver so reruns are idempotent. Use SCD Type 2 where history matters, liquid clustering for layout, and CHECK constraints for invariants.
from delta.tables import DeltaTable
from pyspark.sql import Window

def upsert_silver(batch_df, batch_id):
    latest = (batch_df
        .filter("txn_id IS NOT NULL AND amount > 0")
        .withColumn("rn", F.row_number().over(Window.partitionBy("txn_id").orderBy(F.col("ingested_at").desc())))
        .filter("rn = 1").drop("rn"))
    (DeltaTable.forName(spark, "fraud_prod.silver.transactions").alias("t")
        .merge(latest.alias("s"), "t.txn_id = s.txn_id")
        .whenMatchedUpdateAll().whenNotMatchedInsertAll().execute())

(spark.readStream.table("fraud_prod.bronze.transactions")
    .writeStream.foreachBatch(upsert_silver)
    .option("checkpointLocation", "/Volumes/fraud_prod/bronze/checkpoints/silver_txn")
    .trigger(availableNow=True)
    .start())
4. Gold: model data for consumers
Build star schemas, business aggregates, Customer 360 views and ML feature tables, shaped for the people and tools that read them.
CREATE OR REPLACE TABLE fraud_prod.gold.daily_channel_summary
CLUSTER BY (txn_date) AS
SELECT txn_date, channel, COUNT(*) AS txns, SUM(amount) AS total_amount,
       COUNT_IF(is_flagged) AS flagged_txns
FROM fraud_prod.silver.transactions
GROUP BY txn_date, channel;
Alternative for steps 2–4: a Lakeflow Declarative Pipeline declares streaming tables with expectations (data-quality rules), AUTO CDC for upserts and SCD2, and materialized views for gold; Databricks then manages orchestration, retries, incremental processing and lineage. Choose it for standard medallion flows; hand-written jobs for complex custom logic.
5. Orchestrate and deploy as code
Run the layers as tasks of a Lakeflow Job (bronze → silver → gold) on a schedule or a file-arrival trigger, with retries, timeouts and failure alerts, on job compute or serverless. Define jobs, pipelines and their settings in a Databricks Asset Bundle, keep code in Git, test in CI, and deploy the same bundle to dev, test and prod with a service principal.
6. Govern access
GRANT USE CATALOG ON CATALOG fraud_prod TO `fraud-analysts`;
GRANT USE SCHEMA, SELECT ON SCHEMA fraud_prod.gold TO `fraud-analysts`;

-- column mask: only the pii-readers group sees full card numbers
CREATE FUNCTION fraud_prod.silver.mask_pan(pan STRING) RETURNS STRING
RETURN CASE WHEN is_account_group_member('pii-readers') THEN pan
            ELSE concat('XXXX-XXXX-XXXX-', right(pan, 4)) END;
ALTER TABLE fraud_prod.silver.cards ALTER COLUMN pan SET MASK fraud_prod.silver.mask_pan;

-- row filter: analysts see only their region
CREATE FUNCTION fraud_prod.silver.region_filter(region STRING) RETURNS BOOLEAN
RETURN is_account_group_member('fraud-admins') OR region = 'IN-WEST';
ALTER TABLE fraud_prod.silver.transactions SET ROW FILTER fraud_prod.silver.region_filter ON (region);
Unity Catalog also records lineage automatically (table and column level), keeps audit logs in system tables, and supports tags (e.g. PII) for discovery and policy.
7. Performance and maintenance
  • Liquid clustering on common filter columns instead of over-partitioning.
  • Predictive optimization (or scheduled OPTIMIZE and VACUUM) to compact files and clean old versions.
  • Photon-enabled SQL warehouses and right-sized job compute; auto-termination everywhere.
8. Serve and share
Serverless SQL warehouses for BI tools (Power BI, Tableau) and AI/BI dashboards, Genie for natural-language questions, feature tables and Model Serving for ML, and Delta Sharing to share live data with other teams or partners without copying it.
9. Environments, monitoring and cost
  • Separate dev, test and prod catalogs (ideally separate workspaces), bound to their workspaces; masked or synthetic data below prod.
  • Monitor job failures and durations with alerts, data quality with expectations or monitoring, and cost and usage through system tables, with tags for chargeback.
Follow-up questions to expect
Follow-upShort answer
Why bronze, silver and gold?Bronze keeps raw history for replay and audit; silver gives clean, conformed entities; gold serves specific consumers. Each layer can be rebuilt from the one before
Managed or external tables?Managed by default (Unity Catalog handles storage, optimization and cleanup); external when files must live at a path other tools also use
Unity Catalog vs Hive metastore?UC is account-level and cross-workspace, with fine-grained permissions, lineage, auditing, volumes and sharing; the Hive metastore is per workspace with coarse access control
Auto Loader vs COPY INTO?Both are incremental and idempotent; Auto Loader scales to millions of files with schema evolution and notifications, COPY INTO is a simple SQL command for smaller volumes
Declarative pipelines vs jobs?Pipelines for standard medallion flows with built-in data quality and CDC; jobs with custom code for complex logic and full control
How do you control cost?Serverless or job compute instead of always-on clusters, auto-termination, cluster policies, right-sized warehouses, file compaction, and cost dashboards from system tables

6. Delta Lake Deep Dive

Ten questions interviewers ask to check that you understand how Delta works underneath, not just its syntax. Behaviour marked "measured" was verified on Spark 3.5 with Delta 3.2.

Q1.What is the difference between Delta Lake and a Delta table?
Delta Lake is the open-source storage framework: an open table protocol plus libraries for Spark, Flink, Trino, Python (delta-rs) and others. It defines how a transaction log on top of Parquet files gives ACID transactions, time travel and schema enforcement. A Delta table is one concrete table stored in that format: a directory of Parquet data files plus a _delta_log folder.
Delta LakeDelta table
What it isThe format, protocol and librariesOne dataset stored in that format
AnalogyLike "the Parquet format" or "a database engine"Like one Parquet dataset, or one table in that database
ExampleAdding delta-spark to a Spark sessions3://lake/silver/orders/ with its _delta_log, or catalog table silver.orders
A Delta table can be managed (the catalog owns the files; dropping the table deletes data) or external (files at a path you own; dropping removes only the metadata). The data itself is plain Parquet, which is why removing the _delta_log leaves you with ordinary, but no longer consistent, Parquet files.
Q2.How does Delta Lake provide ACID transactions?
PropertyHow Delta achieves it
AtomicityWriters first write new Parquet files, then make them visible in one step by creating the next numbered commit file in _delta_log (e.g. 00000000000000000012.json). The commit file either exists completely or not at all; files not listed in a commit are invisible
ConsistencySchema enforcement rejects writes whose columns or types do not match (measured: appending an INT column to a BIGINT column failed with DELTA_FAILED_TO_MERGE_FIELDS), plus NOT NULL and CHECK constraints
IsolationOptimistic concurrency control: each writer reads a snapshot, writes files, then tries to commit version N+1. If another writer committed first, Delta checks whether the two changes logically conflict (e.g. both touched the same files); if not, it retries the commit on top, otherwise it fails with an error such as ConcurrentAppendException. Readers always see a consistent snapshot (snapshot isolation)
DurabilityData and commit files are stored in durable object storage (S3, ADLS, GCS) once the commit succeeds
The atomic "create commit N only if it does not exist" step needs mutual exclusion from the storage. HDFS and ADLS provide it natively; on S3, Delta historically needed a coordinator (e.g. a DynamoDB-based LogStore) for safe multi-cluster writes, which Databricks handles for you; newer S3 conditional writes help close this gap.
Q3.What is the purpose of _delta_log?
It is the table's transaction log and the single source of truth for which files make up each version. Every commit is a JSON file of actions:
ActionMeaning
protocolMinimum reader/writer versions and table features required
metaDataSchema, partition columns, table properties (e.g. CDF enabled)
add / removeData files added to or logically removed from the table, with per-file statistics (row count, min/max, null counts) used for data skipping
commitInfoOperation, user, timestamp and metrics (shown by DESCRIBE HISTORY)
txnApplication ID and version for idempotent writes (used by streaming and txnAppId/txnVersion)
s3://lake/silver/orders/_delta_log/
  00000000000000000000.json             ← commit 0 (measured: protocol, metaData, add, commitInfo)
  …
  00000000000000000010.checkpoint.parquet   ← full table state at version 10
  00000000000000000011.json
  _last_checkpoint                       ← points readers to the latest checkpoint
To read a version, Delta loads the latest checkpoint (a Parquet snapshot of the state, written every 10 commits by default: measured at version 10) and replays the JSON commits after it. Without checkpoints, a table with 100,000 commits would need 100,000 small files read on every query. Statistics in the log also let some queries finish without reading data at all (measured: count() was answered from log stats).
Q4.How does MERGE work internally?
MERGE runs in two phases and, by default, rewrites whole files (copy-on-write):
Phase 1: find the touched files
  inner-join SOURCE with TARGET on the ON condition (pruning target files with
  partition values and min/max stats) → the list of target files containing at least one match

Phase 2: rewrite those files
  join SOURCE with only the touched files → for each row apply the clauses:
    matched   → UPDATE / DELETE
    unmatched → INSERT (whenNotMatched)
    untouched rows in touched files → copied unchanged into the new files
  commit: "remove" the touched files + "add" the new files, in ONE atomic commit
Measured: a MERGE that updated 5 rows and inserted 1 copied 745 unchanged rows and replaced 3 files with 1 new file. That rewrite of untouched rows is why MERGE can be expensive, and why you should:
  • Deduplicate the source to one row per key first: two source rows matching one target row fail with "multiple source rows matched".
  • Add partition or clustering columns to the ON condition so phase 1 prunes most files.
  • Enable deletion vectors, so updates and deletes mark rows as deleted in a small side file instead of rewriting whole files (merge-on-read), with OPTIMIZE cleaning up later.
  • Note: a MERGE with only WHEN NOT MATCHED INSERT is optimised into an anti-join plus append, with no file rewrites.
Q5.What is time travel?
Every commit creates a new table version, and old data files are not deleted immediately, so you can query the table as of a past version or time:
DESCRIBE HISTORY silver.orders;                                    -- versions, operations, users
SELECT * FROM silver.orders VERSION AS OF 42;
SELECT * FROM silver.orders TIMESTAMP AS OF '2026-10-30 06:00:00';
RESTORE TABLE silver.orders TO VERSION AS OF 42;                   -- roll back a bad load

spark.read.format("delta").option("versionAsOf", 42).load(path)
Uses: rolling back bad loads, auditing ("what did the report see at 6 am?"), reproducing ML training data, and comparing versions to debug pipelines. Limits: log history is kept for delta.logRetentionDuration (30 days by default), and old files are only guaranteed until VACUUM removes them (delta.deletedFileRetentionDuration, 7 days by default).
Q6.What happens when a Spark job fails during a Delta write?
Because data files are written before the commit and only the commit makes them visible, a failure leaves the table exactly as it was:
Failure pointResult
A task fails and is retried successfullyNormal; only the successful attempt's files are committed
The job fails before the commitNo new version; readers see the previous version; files already written by finished tasks stay on storage as orphans, unreferenced by the log
Two writers conflict at commit timeThe loser re-checks for logical conflicts and retries, or fails with a concurrent-modification exception
Failure after the commit succeeded (e.g. the driver dies before reporting success)The data IS committed; a naive rerun of an append would duplicate it
Measured: a job that failed in the write stage left the table at version 0 with all 1,000 rows, and 4 orphan files on disk. VACUUM deletes such orphans later. To make reruns safe, write idempotently: replaceWhere / partition overwrite, MERGE on keys, or txnAppId + txnVersion options (measured: writing the same txnAppId/txnVersion twice stored the row once). Structured Streaming does this automatically with checkpoints plus the log's txn actions.
Q7.What is VACUUM?
VACUUM physically deletes data files that are no longer referenced by the current table version and are older than the retention threshold (7 days by default). It cleans up files removed by updates, deletes, MERGE, OPTIMIZE and overwrites, plus orphans from failed writes. It does not touch the transaction log.
VACUUM silver.orders;                      -- default retention (7 days)
VACUUM silver.orders RETAIN 168 HOURS;
VACUUM silver.orders DRY RUN;              -- list what would be deleted
  • It limits time travel: versions that need deleted files can no longer be read. Measured trap: after VACUUM RETAIN 0 HOURS, count() on version 0 still returned 1,000 (answered from log statistics), but actually reading version 0 failed because its files were gone.
  • A safety check blocks retention under 7 days; lowering it can delete files that long-running readers or streams still need.
  • In open-source Delta, schedule VACUUM yourself; Databricks predictive optimization can run it automatically.
Q8.What is OPTIMIZE and ZORDER?
OPTIMIZEOPTIMIZE … ZORDER BY (cols)
PurposeFix the small-files problemImprove data skipping on frequently filtered columns
What it doesBin-packs many small files into fewer large ones (around 1 GB by default)Also sorts data along a multi-dimensional (Z-order) curve so similar values of several columns are stored in the same files
Effect on queriesFewer files to open and listNarrow min/max ranges per file, so filters on those columns skip most files
CostRewrites small files only; idempotentRewrites the selected data; not incremental
OPTIMIZE silver.transactions;                                    -- compaction only
OPTIMIZE silver.transactions WHERE txn_date >= '2026-10-01';     -- just recent partitions
OPTIMIZE silver.transactions ZORDER BY (account_id, merchant_id);
OPTIMIZE is a normal commit (remove small files, add big ones), so readers are unaffected and old files remain for time travel until VACUUM. Z-order high-cardinality columns used in filters (not partition columns), and keep it to a few columns. For new tables, liquid clustering (CLUSTER BY) replaces both partitioning and Z-ORDER: it is incremental and its keys can be changed without rewriting the table.
Q9.What is the difference between Delta Lake and Apache Iceberg?
Both are open table formats that add ACID transactions, schema evolution and time travel to Parquet files in object storage. The differences are in design and ecosystem:
Delta LakeApache Iceberg
MetadataOrdered transaction log of JSON commits + Parquet checkpointsTree: catalog pointer → metadata.json → manifest list → manifests
PartitioningHive-style partitions or liquid clusteringHidden partitioning with transforms (days(ts), bucket(n, id)); partition evolution without rewrites
Schema evolutionColumn mapping (by name/ID) enables rename and dropColumn IDs from the start; safe rename, drop, reorder
Row-level changesCopy-on-write, or deletion vectorsCopy-on-write or merge-on-read with position/equality delete files (deletion vectors in format v3)
BranchingNo branches (shallow/deep clones instead)Branches and tags for write-audit-publish
Change feedChange Data FeedIncremental reads between snapshots, changelog views
Catalogs and enginesDeepest in Databricks/Spark; Unity Catalog; growing support elsewhereEngine-neutral spec and REST catalog; Spark, Flink, Trino, Athena, Snowflake, BigQuery, Dremio
In interviews, avoid "X is better": choose by primary engine and catalog. The formats are converging: Delta UniForm writes Iceberg metadata for the same files, and tools like Apache XTable translate between formats. See the Delta Lake and Apache Iceberg guides for details.
Q10.How would you implement CDC using Delta Lake?
"CDC with Delta" has two directions; good answers cover both.
A. Ingest CDC from a source database into Delta
Debezium / AWS DMS / Lakeflow Connect ──► bronze_orders_cdc (append-only: op, before/after, commit ts)
   ──► dedupe: keep the LATEST change per key in each batch (order by commit sequence)
   ──► MERGE into silver.orders: op = 'D' → delete, otherwise upsert
from pyspark.sql import functions as F, Window
from delta.tables import DeltaTable

def apply_cdc(batch_df, batch_id):
    latest = (batch_df
        .withColumn("rn", F.row_number().over(
            Window.partitionBy("order_id").orderBy(F.col("commit_lsn").desc())))
        .filter("rn = 1").drop("rn"))                       # one change per key, or MERGE fails
    (DeltaTable.forName(spark, "silver.orders").alias("t")
        .merge(latest.alias("s"), "t.order_id = s.order_id")
        .whenMatchedDelete(condition="s.op = 'D'")
        .whenMatchedUpdateAll(condition="s.commit_lsn > t.commit_lsn")   # ignore stale replays
        .whenNotMatchedInsertAll(condition="s.op <> 'D'")
        .execute())

(spark.readStream.table("bronze.orders_cdc")
    .writeStream.foreachBatch(apply_cdc)
    .option("checkpointLocation", "/chk/silver_orders_cdc")
    .trigger(availableNow=True)
    .start())
On Databricks the declarative equivalent is AUTO CDC … KEYS (order_id) SEQUENCE BY commit_lsn in Lakeflow Declarative Pipelines, which also handles out-of-order events and can store SCD Type 2 history.
B. Produce CDC from a Delta table (Change Data Feed)
ALTER TABLE silver.orders SET TBLPROPERTIES (delta.enableChangeDataFeed = true);

changes = (spark.readStream.format("delta")
    .option("readChangeFeed", "true")
    .table("silver.orders"))
# columns: the row + _change_type (insert / update_preimage / update_postimage / delete),
#          _commit_version, _commit_timestamp
Measured: after an update and a delete, the feed returned the row before the update (update_preimage), after it (update_postimage) and the deleted row (delete). Downstream jobs read only these changes to update gold tables, search indexes or other systems, instead of re-reading the whole table.

7. Hadoop, HDFS & Hive

Still common for roles that touch legacy or on-prem clusters.

Q1.Describe HDFS architecture.
A NameNode holds the filesystem metadata (namespace, block locations); DataNodes store the blocks (128 MB by default) and send heartbeats and block reports. Blocks are replicated (factor 3 by default) across racks for fault tolerance.
Q2.Why is HDFS bad with many small files?
Every file and block is an object in NameNode memory, so millions of tiny files exhaust it, and each file spawns its own map task. Compact files, use container formats (Parquet, ORC, SequenceFile) or Hive/Delta compaction.
Q3.Managed vs external tables in Hive?
Dropping a managed table deletes both metadata and data. Dropping an external table deletes only the metadata, so the files stay. Use external tables for data shared with other tools.
Q4.Partitioning vs bucketing in Hive?
Partitioning splits data into directories by a low-cardinality column (date, country) so queries prune whole folders. Bucketing hashes a high-cardinality column into a fixed number of files, helping joins and sampling. Over-partitioning on high-cardinality columns creates the small-files problem.
Q5.How does HDFS achieve fault tolerance?
Blocks are replicated (default 3) with rack awareness: one copy local, two on another rack. DataNodes send heartbeats every 3 s; a node silent for ~10.5 min is marked dead and its blocks are re-replicated. Checksums catch corrupt blocks, which are read from and replaced by another replica. NameNode HA uses an Active/Standby pair with JournalNodes and ZooKeeper failover.
Q6.A 10 MB file is stored in HDFS with a 128 MB block size. How much space does it use?
About 10 MB per replica (30 MB with replication factor 3). Blocks are a maximum, not an allocation. The real cost is ~150 bytes of NameNode memory per file and block object, which is why millions of small files hurt.
Q7.What were Hive's main problems and how were they solved?
MapReduce latency, no UPDATE/DELETE/MERGE, no isolation, small files, slow partition listing and silent NULLs from schema-on-read. Hive improved with Tez, LLAP, vectorization, a cost-based optimizer and ACID tables. Today Delta, Iceberg and Hudi provide ACID, MERGE, time travel and file-level metadata, queried by Spark SQL or Trino, while the Hive Metastore lives on as a catalog.

8. Streaming: Kafka & Kinesis

Know delivery guarantees, ordering and how consumers scale.

Q1.Explain topics, partitions, offsets and consumer groups in Kafka.
A topic is split into partitions, each an ordered, append-only log. Each message has an offset in its partition. Consumers in a group share partitions (one partition is read by at most one consumer in the group), so parallelism is capped by partition count.
Q2.At-most-once, at-least-once and exactly-once?
At-most-once commits the offset before processing (may lose data). At-least-once commits after processing (may duplicate). Exactly-once needs idempotent producers plus transactions in Kafka, or an idempotent/transactional sink, e.g. Spark Structured Streaming with checkpoints writing to Delta.
Q3.How is ordering guaranteed?
Only within a partition (Kafka) or shard (Kinesis). Send related events with the same key so they land in the same partition.
Q4.Kafka vs Kinesis?
Kafka is open source and highly configurable, with long retention and a huge ecosystem, but you run it yourself (or use MSK). Kinesis is fully managed and scales by shards, with tight AWS integration (Firehose, Lambda), but has per-shard throughput limits and shorter default retention.
Q5.What are watermarks in Structured Streaming?
A watermark (withWatermark('event_time', '10 minutes')) tells Spark how late data may arrive. It lets the engine drop old aggregation state and decide when windowed results are final.
Q6.If Spark can read Kafka directly, why would you use NiFi?
Only for sources that cannot publish to Kafka themselves: SFTP/S3 file drops, polled REST APIs, legacy databases, JMS, MQTT. NiFi (or Kafka Connect) gets that data into Kafka with provenance and backpressure. Spark should still read only from Kafka, never from NiFi directly, because Kafka gives replay, offsets and partition-level parallelism.
Q7.What happens to events that arrive after the watermark?
They are silently dropped from event-time operators (windows, event-time joins, timers) but remain in Kafka. That causes undercounting and missed windowed alerts. Mitigate by measuring dropped records, setting the delay from observed lateness, using allowed lateness or side outputs, and reconciling with batch. Never put watermark-dropping operators on a path where every event must be processed.
Q8.Why might a Flink job's windows stop emitting results?
The watermark is the minimum across source partitions, so one idle Kafka partition holds it back and windows never close. Configure source idleness (with_idleness or table.exec.source.idle-timeout).
Q9.What happens during a consumer-group rebalance?
When a consumer joins, leaves or misses heartbeats, partitions are reassigned across the group. With the classic eager protocol all consumers stop and give up their partitions, causing a pause; cooperative (incremental) rebalancing moves only the affected partitions. Commit offsets before partitions are revoked, or another consumer will reprocess those records. Static group membership avoids rebalances on quick restarts.
Q10.How do you handle a poison message?
A record that always fails processing must not block the partition. Catch the error, retry a bounded number of times, then send the record with error metadata to a dead-letter topic and move on. Alert on DLQ volume and provide a way to fix and replay those records.
Q11.How do you choose a topic's partition count?
From target throughput divided by per-partition throughput (measured for both producer and consumer), and from the maximum consumer parallelism you need, since one partition feeds at most one consumer in a group. Leave headroom for growth: adding partitions later changes key-to-partition mapping and breaks per-key ordering for existing keys.
Q12.Consumer lag keeps growing. How do you investigate?
Check whether input volume rose or consumers slowed: per-partition lag (one hot partition means key skew), consumer processing time, slow downstream sinks, frequent rebalances, GC pauses, and errors or retries. Fixes include scaling consumers up to the partition count, batching sink writes, fixing skewed keys, or adding partitions.
Q13.How do you evolve a schema safely?
Register schemas (Avro or Protobuf) in a Schema Registry with a compatibility mode, usually BACKWARD: only add optional fields with defaults, and never remove or retype required fields. Deploy consumers before producers start sending the new version. Breaking changes go to a new topic or versioned subject.
Q14.How do you replay the last three days of data?
If retention covers it, reset the consumer group's offsets to a timestamp (kafka-consumer-groups.sh --reset-offsets --to-datetime … --execute, with the group stopped), or start a new consumer group or job from that time, writing into new tables for a blue/green switch. Sinks must be idempotent so replays do not duplicate. Beyond retention, replay from the lake's bronze copy.

9. AWS & Data Lakes

Focus on the core data services and why you would pick each.

Q1.Data lake vs data warehouse vs lakehouse?
A lake stores raw files of any format cheaply (S3) with schema-on-read. A warehouse stores modeled, structured data with schema-on-write for fast SQL. A lakehouse adds table formats (Delta, Iceberg, Hudi) on top of the lake to provide ACID transactions and warehouse-like performance directly on lake storage.
Q2.What do Glue Crawlers, the Glue Data Catalog and Athena do?
Crawlers infer schemas and partitions from S3 and register tables in the Data Catalog (a Hive-compatible metastore). Athena runs serverless Presto/Trino SQL against those tables and charges per data scanned.
Q3.How do you reduce Athena cost and speed up queries?
Store columnar formats (Parquet/ORC) with compression, partition by common filter columns, use partition projection, avoid tiny files, and select only needed columns. Each cuts bytes scanned, which is what you pay for.
Q4.Choose between S3 storage classes.
Standard for hot data; Intelligent-Tiering when access patterns are unknown; Standard-IA / One Zone-IA for infrequent access; Glacier tiers for archives. Automate transitions with lifecycle policies.
Q5.How does Redshift distribute data?
Via distribution style: KEY co-locates rows with the same key for joins, ALL copies small dimensions to every node, EVEN round-robins, and AUTO lets Redshift choose. Sort keys enable zone-map block skipping.

10. AWS: S3, IAM & Security

Answers are pitched to be said aloud in under a minute. AWS limits and prices change, so check current documentation before quoting exact numbers.

Q1.What consistency model does S3 provide?
Strong read-after-write consistency for PUTs, DELETEs and LISTs in all regions since December 2020, at no extra cost. Jobs can list and read files immediately after writing them, which removed the need for workarounds like EMRFS consistent view.
Q2.How does S3 performance scale?
At least 3,500 PUT/COPY/POST/DELETE and 5,500 GET/HEAD requests per second per prefix, scaling by spreading load across prefixes. Use multipart upload for large objects (recommended above ~100 MB, required above 5 GB; objects up to 5 TB) and byte-range GETs for parallel reads.
Q3.Which S3 encryption would you use for a bank?
Options are SSE-S3 (the default), SSE-KMS, DSSE-KMS and SSE-C. For a bank: SSE-KMS with customer-managed keys (key policies, rotation, CloudTrail audit of key use), S3 Bucket Keys to cut KMS request costs, and a bucket policy denying unencrypted uploads and non-TLS access.
Q4.How do you meet WORM / record-retention requirements on S3?
S3 Object Lock in compliance or governance mode, with retention periods or legal holds, prevents deletion or overwrite. Combine with versioning, lifecycle transitions to Glacier tiers, and replication. Typical for AML and audit records kept for years.
Q5.How do you secure access to S3 buckets?
Block Public Access on, ACLs disabled (bucket-owner-enforced), least-privilege IAM and bucket policies, VPC gateway endpoints so traffic stays private, Access Points per consumer, Lake Formation for table-level access, and CloudTrail data events plus Macie to find PII.
Q6.How do you trigger processing when a file lands in S3?
S3 event notifications to Lambda, SQS or SNS, or via EventBridge for richer filtering, e.g. S3 → EventBridge → Step Functions → Glue. Events can be delivered more than once, so make processing idempotent.
Q7.IAM user vs role vs policy?
A user is a long-lived identity (avoid for workloads). A role is assumed temporarily for short-lived credentials; Glue, EMR and Lambda run with roles. A policy is a JSON document of allowed or denied actions. A role has a trust policy (who may assume it) and permission policies (what it may do).
Q8.How is an AWS request evaluated when policies conflict?
Everything is implicitly denied; an explicit allow is required; an explicit deny anywhere always wins. SCPs, permission boundaries, session, resource and identity policies are all evaluated, and the effective permission is their intersection minus any explicit deny.
Q9.How does a Glue job in account A read an S3 bucket in account B?
Either a bucket policy in B allowing A's Glue role, or a role in B that A's role assumes. If the bucket uses SSE-KMS, B's key policy must also allow A's role. With Lake Formation, use cross-account data sharing instead of raw S3 permissions.
Q10.How do ETL jobs get database passwords?
From Secrets Manager (with automatic rotation for RDS/Redshift) or Parameter Store, read at run time using the job's IAM role. Never in code or plain-text job parameters. Glue connections can reference Secrets Manager directly.
Q11.How do you restrict what accounts can do across an organisation?
AWS Organizations Service Control Policies, e.g. deny any region except the approved in-country ones, deny disabling CloudTrail, require encryption, combined with Control Tower guardrails and AWS Config rules.
Q12.How do you design an S3 data lake layout?
Separate zones (raw/landing, curated, consumption), each with its own prefix or bucket and access policy. Use columnar formats or Delta/Iceberg/Hudi tables, partition by low-cardinality filter columns (usually date), keep files around 128 MB–1 GB, apply lifecycle rules and encryption per zone, register tables in the Glue Catalog, and control access with Lake Formation.
Q13.What are KMS key policies and why do they matter?
Every KMS key has a key policy controlling who can use and manage it; IAM permissions alone are not enough unless the key policy delegates to IAM. For data platforms: separate keys per environment or domain, automatic rotation, and CloudTrail audit of key use.

11. AWS: Glue, EMR & Athena

The processing services: expect "how would you choose" and "how would you debug" questions.

Q1.What are the main components of AWS Glue?
The Data Catalog (Hive-compatible metastore), crawlers, ETL jobs (Spark, Python shell, Ray, streaming), triggers and workflows, Glue Data Quality (DQDL rules), Glue Studio for visual jobs, JDBC connections, and DataBrew for no-code preparation.
Q2.What is a DPU and how do Glue worker types work?
A DPU is 4 vCPU and 16 GB. G.1X = 1 DPU, G.2X = 2 DPU, G.4X/G.8X for memory-heavy jobs, G.025X for low-volume streaming. Billing is per DPU-hour with a 1-minute minimum on recent versions. Auto Scaling adjusts workers; Flex execution runs non-urgent jobs on spare capacity for less.
Q3.DynamicFrame vs DataFrame?
A DynamicFrame tolerates inconsistent schemas ("choice" types) and integrates with the catalog, bookmarks and Glue transforms (resolveChoice, relationalize, ApplyMapping). A DataFrame has a fixed schema and the full Spark API. Common practice: read as a DynamicFrame, toDF() for logic, convert back with DynamicFrame.fromDF() for Glue sinks.
Q4.How do you process data incrementally in Glue?
Job bookmarks track processed S3 files or JDBC key values so reruns pick up only new data; they need transformation_ctx on sources and job.commit(). Alternatives: your own watermark in a control table, reading only new partitions, or MERGE on Iceberg/Delta/Hudi tables.
Q5.How do you read only some partitions of a catalog table in Glue?
A push-down predicate, e.g. push_down_predicate="dt >= '2026-10-01'", so Glue lists and reads only matching partitions. Add catalog partition indexes for tables with many partitions.
Q6.A Glue job is slow or out of memory. What do you check?
Spark UI and CloudWatch: skew (one long task), small files (groupFiles/groupSize or compact upstream), partition counts, large shuffles (broadcast small tables), driver collects, worker type (move to G.2X+), missing push-down predicates, and Python UDFs that could be built-ins.
Q7.When should you use Glue crawlers, and when not?
Crawlers are handy for discovery and changing schemas, but they cost money and can create unwanted tables or schema changes. For known, stable layouts, define tables in code/IaC and add partitions via the API, MSCK REPAIR or Athena partition projection.
Q8.Glue vs EMR: how do you choose?
Glue: serverless, quick to start, pay per job; good for spiky or moderate ETL and teams without cluster skills. EMR: large or continuous workloads, deep tuning, custom frameworks (Flink, Presto, HBase), spot savings. EMR Serverless sits in between. Decide on cost at scale, control, skills and operational overhead.
Q9.Explain EMR node types.
Primary: runs the YARN ResourceManager and HDFS NameNode. Core: run tasks and store HDFS blocks, so losing them can lose data. Task: compute only, ideal for spot instances. Keep data in S3 so clusters can be transient.
Q10.EMR on EC2 vs EMR Serverless vs EMR on EKS?
EMR on EC2: full control over instances, bootstrap actions and frameworks. EMR Serverless: submit Spark/Hive jobs without managing clusters, with optional pre-initialised capacity. EMR on EKS: run Spark on an existing Kubernetes cluster to share infrastructure.
Q11.How do you use spot instances safely on EMR?
Spot for task nodes (core nodes only if HDFS loss is acceptable), instance fleets with several instance types, on-demand for the primary node, managed scaling, Spark task retries, outputs in S3 and checkpoints for long jobs.
Q12.How do you migrate on-prem Hadoop to EMR?
Move HDFS data to S3 with DataSync, Snowball or DistCp; move the Hive metastore to the Glue Catalog; port Spark/Hive jobs (mostly path changes from hdfs:// to s3://); replace Oozie with Step Functions or MWAA; reconcile outputs; prefer transient clusters.
Q13.What is Athena partition projection?
Athena calculates partition locations from configured patterns (such as date ranges) instead of looking them up in the Glue Catalog. No crawlers or MSCK REPAIR needed, and queries on heavily partitioned tables plan faster.
Q14.CTAS vs INSERT INTO vs UNLOAD in Athena?
CTAS creates a new table from a query with a chosen format and partitioning (great for CSV → Parquet). INSERT INTO appends results to an existing table. UNLOAD writes results to S3 in a chosen format without creating a table.
Q15.Can Athena update or delete rows? Athena vs Redshift?
Yes, on Apache Iceberg tables (UPDATE, DELETE, MERGE, time travel, OPTIMIZE/VACUUM); plain Hive tables are append-only. Athena is serverless pay-per-query SQL for ad-hoc work on S3; Redshift is a warehouse for heavy, concurrent, repeated BI workloads with predictable performance. Many platforms use both.
Q16.How do you run data-quality checks in Glue?
Glue Data Quality with DQDL rules (e.g. RowCount > 0, IsComplete "txn_id", IsUnique "txn_id", ColumnValues "amount" > 0) evaluated in jobs or on catalog tables, with results sent to CloudWatch/EventBridge to stop pipelines or alert. Alternatively Deequ or Great Expectations inside the Spark job. Glue streaming jobs run Structured Streaming on Kinesis or MSK with S3 checkpoints.
Q17.Transient vs long-running EMR clusters? Bootstrap actions vs steps?
Transient clusters are created per pipeline run, run their steps and terminate: cheapest and clean. Long-running clusters serve interactive use or continuous streaming and need managed scaling, monitoring and patching. Keep state in S3 and the Glue Catalog so clusters are disposable. Bootstrap actions run scripts on every node at start-up; steps are units of work (spark-submit, Hive scripts) that orchestrators add and wait on.
Q18.How do you tune and secure Spark on EMR?
Tune: ~5 cores per executor with 4–8 GB per core, shuffle partitions from data size, AQE with skew-join handling, broadcast small tables, Parquet with partition pruning, no small files; explicit sizing beats maximizeResourceAllocation in production. Secure: security configurations for encryption at rest and in transit, Kerberos or Lake Formation for fine-grained access, private subnets, least-privilege instance profiles and service roles.
Q19.How do you query data outside S3 from Athena?
Federated queries through Lambda-based connectors (RDS, DynamoDB, Redshift and others) registered as data sources, joinable with S3 tables in one query.

12. AWS: Redshift, Lambda & Orchestration

Warehouse internals and how pipelines are wired together.

Q1.Explain Redshift's architecture.
Massively parallel and columnar: a leader node plans and coordinates; compute nodes, split into slices, store data and execute in parallel. RA3 nodes separate compute from managed storage on S3. Redshift Serverless bills in RPU-hours and scales automatically.
Q2.What are Redshift sort keys?
They order data on disk so range filters skip blocks using zone maps. Compound sort keys work best when filters use the leading column (often date first); interleaved keys weight several columns equally but cost more to maintain; AUTO is common now.
Q3.What is the fastest way to load Redshift?
COPY from S3 in parallel: many compressed files of roughly equal size (a multiple of the slice count, ~100 MB–1 GB each), columnar formats or gzip CSV, a manifest for exact file lists, and an IAM role. Avoid single-row INSERTs; use staging tables + MERGE for upserts.
Q4.How do you implement SCD Type 2 in Redshift?
Load changes into a staging table, then in one transaction MERGE (or UPDATE + INSERT): close current rows whose tracked attributes changed (end date, current flag false), and insert new current rows with new surrogate keys and effective dates.
Q5.What is Redshift Spectrum? How does Redshift handle concurrency?
Spectrum queries S3 data through external tables in the Glue Catalog without loading it, so hot data lives in Redshift and cold data stays in S3, joinable in one query. Concurrency is handled by workload management queues, query priorities, concurrency scaling for bursts, short-query acceleration, and Serverless auto-scaling.
Q6.What maintenance does Redshift need, and how do you share data?
VACUUM and ANALYZE (largely automatic now), automatic compression encodings (AZ64, ZSTD), and materialized views with auto refresh. Data sharing gives live, read-only access across clusters, workgroups and accounts without copying. Semi-structured data goes into the SUPER type queried with PartiQL.
Q7.What are AWS Lambda's key limits, and when should you use it in a pipeline?
15 minutes per invocation, 128 MB–10 GB memory (CPU scales with it), up to 10 GB /tmp, payload limits, and regional concurrency limits (1,000 by default). Use it for light, event-driven work: validating or routing a file, starting a Glue job or state machine, calling an API, notifications. Not for heavy or long ETL.
Q8.How do you make Lambda processing reliable?
Async invocations are retried, so make handlers idempotent (e.g. record processed keys in DynamoDB). Configure retries, on-failure destinations or DLQs, partial batch responses for SQS, and CloudWatch alarms on errors and throttles. Share dependencies with layers or container images (up to 10 GB).
Q9.Step Functions Standard vs Express workflows?
Standard: runs up to a year, exactly-once step execution, full history; right for data pipelines. Express: up to 5 minutes, high volume, at-least-once, cheaper per execution; right for event processing.
Q10.How does Step Functions wait for a Glue job, and how do you handle errors?
Use the .sync integration (glue:startJobRun.sync): the state starts the job, waits, and fails if the job fails (.waitForTaskToken for custom callbacks). Handle errors with Retry (backoff on specific errors), Catch (route to SNS, an audit table or cleanup) and Choice (e.g. stop if reconciliation fails). The Map state fans out over items; Distributed Map handles millions of S3 objects.
Q11.When would you choose MWAA over Step Functions? What does EventBridge add?
MWAA (managed Airflow) for complex schedules and dependencies, date backfills, many non-AWS systems, or an existing Airflow team; tasks must be idempotent. Step Functions for serverless AWS-native, event-driven flows. EventBridge routes events (S3, Glue state changes, custom) to targets and its Scheduler provides cron-style triggers.

13. AWS: Migration, Governance & Streaming

Migration and governance questions are common for senior and banking roles.

Q1.How does AWS DMS work?
A replication instance (or DMS Serverless) connects source and target endpoints and runs tasks: full load, CDC only, or full load + CDC. CDC reads the source transaction log (e.g. Oracle LogMiner, SQL Server CDC) and applies changes to targets such as S3, Redshift, Aurora or Kinesis.
Q2.How do you migrate a large Oracle database with minimal downtime?
Convert schema with SCT or DMS Schema Conversion, run DMS full load + CDC, validate with DMS data validation plus your own reconciliation, keep CDC running until cut-over, freeze writes briefly, let CDC catch up, switch applications, and keep a rollback plan.
Q3.How do you move large volumes of files from on-premises?
DataSync for online, scheduled, verified transfers over the network or Direct Connect; Snowball for tens of TB to PB offline; Transfer Family for partners delivering files over SFTP into S3. For Teradata/Netezza, SCT extraction agents or native export tools to S3, then COPY into Redshift.
Q4.How would you migrate SAS workloads to AWS?
Inventory and score programs and retire dead code; land datasets as Parquet/Iceberg on S3; convert DATA steps and PROCs to PySpark on Glue or EMR (macros → Python functions, formats → lookup tables); orchestrate with Step Functions or MWAA; reconcile every program against SAS outputs; parallel run and cut over in waves.
Q5.What SAS behaviours cause reconciliation mismatches?
Dates counted from 1960-01-01, missing values that are smaller than any number and sort first, special missings (.A–.Z), user formats, latin1 encoding, floating-point money, trailing blanks ignored in comparisons, implicit sort order and many-to-many MERGE behaviour.
Q6.What does Lake Formation add on top of IAM and S3 policies?
Database-, table-, column-, row- and cell-level permissions on catalog tables, enforced by Athena, EMR, Glue and Redshift Spectrum; LF-Tags for tag-based access at scale; cross-account sharing; CloudTrail audit. It replaces complex bucket policies for analytics access.
Q7.How would you implement a data mesh on AWS?
Each domain account owns its S3 data and catalog databases; a central governance account uses Lake Formation to share tables across accounts (via RAM) with LF-Tags; consumers query with Athena, EMR or Redshift; Amazon DataZone adds a business catalog and publish/subscribe workflow. Use Macie and Glue sensitive-data detection to find PII and drive tags.
Q8.Kinesis Data Streams vs Amazon MSK? What is Firehose for?
Kinesis: fully managed and AWS-native, scaled by shards (provisioned: ~1 MB/s or 1,000 records/s in and 2 MB/s out per shard) or on-demand, retention up to a year, simple Lambda/Firehose integration. MSK: managed Kafka with its APIs and ecosystem, better if you already use Kafka or need portability. Firehose loads streams into S3, Redshift or OpenSearch with buffering, optional Lambda transforms and Parquet conversion, with no consumer code.
Q9.How do you process streams on AWS?
Managed Service for Apache Flink, Glue streaming jobs, Spark Structured Streaming on EMR, or Lambda for simple per-record work, with checkpoints in S3 and output to Iceberg/Delta/Hudi tables or serving stores.

14. AWS: Monitoring, Cost & Scenarios

Scenario questions test whether you can combine services into a working, secure, idempotent pipeline.

Q1.How do you monitor data pipelines on AWS?
CloudWatch metrics, logs and alarms (Glue job metrics, EMR, Lambda errors, Step Functions failures), EventBridge rules on job state changes → SNS, CloudTrail for API audit, and data-level checks (row counts, freshness, DQ results) written to an audit table or dashboard.
Q2.How do you reduce the cost of an AWS data platform?
Spot and Graviton on EMR, transient clusters, Glue Flex and auto scaling, right-sized workers, S3 lifecycle rules and Intelligent-Tiering, Parquet + partitioning for Athena, Redshift reserved capacity or Serverless for spiky use, Savings Plans, tags and budgets with Cost Explorer, and shutting down idle resources.
Q3.A Lambda step needs more than 15 minutes. What do you do?
The limit is fixed, so move the work: have Lambda (or EventBridge) start Glue, EMR Serverless, ECS Fargate, AWS Batch or a Databricks job; orchestrate multi-step flows with a Standard Step Functions workflow using .sync integrations; or split the work with Distributed Map or SQS fan-out to idempotent workers. If it is only slightly over, more memory (which adds CPU) may be enough. Never loop a Lambda by having it invoke itself.
Q4.Design a daily pipeline: a partner sends a CSV over SFTP and it must reach Redshift validated.
Transfer Family (SFTP) → S3 landing → EventBridge on object created → Step Functions: (1) Lambda validates file name and size; (2) Glue converts to Parquet, cleans and dedupes into the curated zone; (3) Glue Data Quality and reconciliation against the control file, and on failure SNS and stop; (4) Redshift COPY into staging + MERGE into the target; (5) audit-table update; (6) SNS success. Idempotent by file key, KMS-encrypted, with CloudWatch alarms.
Q5.Design near-real-time CDC from Oracle into the lake.
DMS full load + CDC from Oracle to S3 (or Kinesis/MSK) → a Glue or EMR streaming job MERGEs changes into Iceberg/Hudi/Delta tables → Glue Catalog → Athena / Redshift Spectrum. Schedule compaction, monitor DMS replication latency, and reconcile counts daily against the source.
Q6.Design a secure data lake for an Indian bank on AWS.
Accounts per environment and domain under AWS Organizations, with SCPs restricting regions to the two Indian regions; S3 with SSE-KMS customer-managed keys, Block Public Access and Object Lock for retention; VPC endpoints and no public access; Lake Formation with LF-Tags, row and column filters; Macie for PII; tokenised account and card numbers; CloudTrail, Config and GuardDuty; DR across the two Indian regions.
Q7.A nightly Glue job that took 30 minutes now takes 3 hours. How do you investigate?
Compare input volume and file counts (a small-file explosion?), check the Spark UI for skew and spills, look for schema changes causing type coercion, missing push-down predicates reading every partition, changed join cardinality from duplicates, worker type and auto-scaling caps, and JDBC source throttling. Fix the root cause, then add volume and duration alerts.
Q8.How do you make AWS pipelines idempotent and handle duplicate or late files?
Track processed files in a control table (DynamoDB or an audit table), overwrite target partitions instead of appending, MERGE on business keys, dedupe on keys within a window, and parameterise reprocessing by date so backfills give the same result.
Q9.How would you migrate an on-prem Hadoop + Hive + Oozie platform to AWS?
Assess jobs and data; move data with DataSync, Snowball or DistCp to S3; Hive metastore → Glue Catalog; Spark/Hive jobs → EMR (or Glue / EMR Serverless); Oozie → Step Functions or MWAA; security via Lake Formation; reconcile outputs during a parallel run; decommission wave by wave.

15. Governance & Compliance

Expected for banking, insurance and senior roles.

Q1.How would you set up data governance in a federated (data mesh) organisation?
Domains own data as products with named owners and stewards; a central council sets a few global rules (classification, privacy, residency, identifiers, minimum quality and metadata, retention); the platform enforces them as code: publishing fails without owner and classification, tag-based masking, contract tests in CI/CD, quarantine on DQ failure. Start with 2–3 domains and measure ownership coverage, DQ scores and access lead time.
Q2.What is BCBS 239 and how do you meet it as a data engineer?
The Basel Committee's 14 principles for risk data aggregation and reporting: governance, architecture, accuracy, completeness, timeliness, adaptability and reporting quality. In practice: identify critical data elements behind risk reports, give each an owner, definition, lineage, DQ rules and reconciliation to the ledger; remove manual spreadsheet steps; set SLAs; keep evidence (scorecards, reconciliation logs, lineage) for supervisors.
Q3.How do you implement lineage and data quality at enterprise scale?
Capture lineage automatically (Unity Catalog, Purview, OpenLineage from Spark/dbt/Airflow) at table and column level. Run DQ rules as code (Great Expectations, Deequ, dbt tests, Soda, Glue DQ) at ingestion, transformation and consumption, with severities that fail, quarantine or warn. Publish scorecards in the catalog, route issues to stewards, and start with critical data elements.
Q4.How do you handle data residency and privacy in a multi-cloud architecture?
One global control plane for catalog, classification and policy-as-code, with regional data planes where raw PII stays. Restrict regions with org policies, tokenise identifiers at ingestion with an in-country token vault, use bank-controlled per-region keys, apply ABAC, row filters and masking consistently, and let only aggregated, anonymised or tokenised data cross borders. Remember backups, logs, test data, SaaS tools and AI prompts.
Q5.Which regulations matter for a banking data engineer?
AML/KYC with suspicious-transaction reporting, sanctions screening, fraud risk directions, privacy laws (DPDP, GDPR), payment-data localisation (RBI requires payment data stored only in India), PCI DSS for card data, BCBS 239 for risk data, and IT/cyber rules (RBI IT governance, DORA). In practice: tokenise PII and card data, keep data in-country, enforce retention and deletion, keep audit trails, lineage and reconciliation, and use least-privilege access.
Q6.How would you handle a data-subject deletion request when AML rules require retention?
Legal decides which obligation wins per data category. Technically: find the person's data through lineage, delete or anonymise what is not under a retention obligation, and use crypto-shredding (delete the token-vault entry or per-subject key) so retained records can no longer be linked to the person. Log the request and actions for audit.

16. Pipelines, Incremental Load & Orchestration

Design-thinking questions: correctness, reruns and failures.

Q1.What does idempotent mean for a pipeline, and how do you achieve it?
Running it twice for the same input produces the same result. Achieve it with overwrite-by-partition instead of blind appends, MERGE/upserts on a business key, and deterministic run parameters (process "the date passed in", not "now").
Q2.Full load vs incremental load? How do you implement incremental?
A full load reprocesses everything; incremental processes only new or changed data. Common approaches: a high-watermark column (updated_at or an ID), CDC from database logs (Debezium, DMS), or tracking processed files (Auto Loader, S3 event notifications).
Q3.How do you handle late-arriving data?
Reprocess a trailing window (e.g. the last 3 days) on each run, merge on keys so reruns are safe, and in streaming use watermarks. For late dimension rows, load placeholder "unknown" members and update them later.
Q4.How do you backfill a year of data safely?
Make the job idempotent and parameterized by date, run it in parallel chunks with bounded concurrency, write to a staging location and swap or merge on success, and validate row counts and totals against the source.
Q5.What would you monitor and test in a production pipeline?
Freshness, volume (row counts vs expected), schema changes, null/uniqueness/referential checks (Great Expectations, dbt tests), job duration and cost. Alert on failures and anomalies, and route bad records to a quarantine table instead of failing silently.
Q6.What is a DAG in Airflow? What are sensors, retries and catchup?
A DAG is a set of tasks with dependencies and a schedule. Sensors wait for an external condition (file arrives). Retries rerun failed tasks with a delay. catchup=True creates runs for every missed interval since the start date, so set it deliberately.

17. Python for Data Engineers

Usually a short coding exercise plus a few language questions.

Q1.List vs tuple vs set vs dict?
Lists are ordered and mutable; tuples are ordered and immutable (hashable, so usable as dict keys); sets are unordered unique elements with O(1) membership; dicts map keys to values with O(1) lookup.
Q2.What is a generator and why use one for data processing?
A function using yield that produces values lazily, one at a time. It keeps memory flat when streaming large files or API pages, instead of loading everything into a list.
Q3.How would you process a 50 GB CSV on a laptop?
Stream it: read in chunks (pd.read_csv(..., chunksize=...)) or line by line, aggregate incrementally, select only needed columns with explicit dtypes, or use an out-of-core engine like DuckDB or Polars lazy mode.
Q4.Write a function to flatten nested JSON.
def flatten(d, parent="", sep="."):
    out = {}
    for k, v in d.items():
        key = f"{parent}{sep}{k}" if parent else k
        if isinstance(v, dict):
            out.update(flatten(v, key, sep))
        else:
            out[key] = v
    return out

18. Scenario & System Design

Open-ended questions. Clarify requirements first, then walk source → ingest → store → transform → serve, covering scale, failure and cost.

Q1.Design a pipeline that ingests clickstream events and powers a near-real-time dashboard.
Events → Kafka/Kinesis (keyed by user or session) → Spark Structured Streaming with watermarks writing to bronze Delta tables → windowed aggregates to silver/gold → dashboard queries gold through a SQL warehouse. Discuss partition counts for throughput, exactly-once via checkpoints, late events, and a batch reconciliation job.
Q2.A daily job that used to take 1 hour now takes 5. How do you debug it?
Check what changed: input volume, code, cluster config. In the Spark UI, find the slow stage, look for skew (a few long tasks), spills to disk, excessive shuffles, or many small files. Then fix the cause: AQE/salting, broadcast joins, compaction, partition pruning, or right-sizing the cluster.
Q3.Source data arrives with a new column and the pipeline breaks. How do you design for that?
Decide a schema policy per layer: allow additive evolution in bronze (e.g. Delta mergeSchema), enforce contracts in silver/gold, alert on schema drift, and agree on data contracts with source teams.
Q4.How would you migrate an on-prem Hadoop/Hive warehouse to the cloud?
Inventory data and jobs, choose target (S3 + Glue/EMR or Databricks), move data with DistCp or DataSync, convert tables to Parquet/Delta/Iceberg, port jobs incrementally, run old and new in parallel and reconcile outputs before cutover.
Q5.Lambda vs Kappa architecture: which would you choose?
Lambda runs separate batch and speed pipelines: good when you need millisecond decisions plus authoritative batch recomputation, but logic is duplicated and outputs must be reconciled. Kappa uses one streaming pipeline over a replayable log, reprocessing by replaying into new tables, so logic is written once. Choose Kappa when sources are mostly events and seconds of latency are fine; on a lakehouse, Delta tables read as streams make Kappa-style designs natural.
Q6.Real-time fraud scoring runs in Flink and nightly batch in Databricks. How do nightly S3 file drops fit in?
They belong to the batch layer. Validate each file against its control file (row counts, totals, checksum) and quarantine failures, ingest with Auto Loader into bronze, MERGE/SCD2 into silver, join with the day's events, reconcile real-time results against settled data, run a data-quality gate, build gold, and publish refreshed reference data back to Flink. Make it idempotent per business_date.
Q7.When would you add NiFi to a Kafka + Spark pipeline?
When there are many heterogeneous sources (files, APIs, MQ, devices), when a regulated environment needs per-record provenance at ingestion, or when non-developers must add sources without deployments. If all sources are your own apps writing to Kafka, leave it out.
Q8.Walk through how you would build a lakehouse on Databricks from scratch.
Storage first: an S3 bucket with KMS, an IAM role, a storage credential and an external location. Then Unity Catalog objects: a catalog per environment and domain, bronze/silver/gold schemas, volumes for landing files and checkpoints. Ingest with Auto Loader, Kafka streaming or Lakeflow Connect into append-only bronze; clean, dedupe, tokenise and MERGE into silver; build star schemas and aggregates in gold. Orchestrate with a Lakeflow Job in an Asset Bundle, govern with grants, masks and tags, serve via SQL warehouses and dashboards, and automate everything with Terraform and CI/CD.
Q9.When would you use MongoDB rather than a relational database or Delta tables?
MongoDB suits low-latency reads and writes of whole entities with flexible or nested structure, such as the current alert or profile per account served to an application. Relational databases suit transactional integrity across normalised tables. Delta/Iceberg suit large-scale history and analytics. A common pattern is streaming upserts into MongoDB for serving, with Delta keeping the full history.

19. Role-Specific Prep

Tailor answers to the role. For architect-level questions use this order: business objective → options → trade-offs → recommendation → risks and mitigations → roadmap.

Q1.Cloud migration roles: what is the core of the job, and what should you be ready to explain?
The flow is legacy (Oracle, Teradata, mainframe, SAS) → analyse → land data in S3 → rewrite logic in PySpark/Scala on Glue or EMR → load Redshift/Athena → reconcile → orchestrate → cut over and decommission. Reconciliation is the heart of it. Be ready on Glue/EMR internals and sizing, Lambda/Step Functions/Airflow trade-offs, Redshift keys and COPY, star schemas and SCDs, full vs incremental vs CDC extraction, reconciliation techniques, SAS idioms (BY/FIRST./LAST., RETAIN, MERGE, macros), and basic Scala (case classes, Datasets, sbt).
Q2.How do you reconcile a migrated table against the legacy system?
Compare at increasing depth: schema and types; row counts per table and partition; sums and min/max of key numeric columns; null and distinct counts; then row-level hashes on business keys to find exact mismatches. Allow tolerances for floating-point and rounding differences, record every run in an audit table, and require business sign-off before cut-over.
Q3.Data engineer vs data architect: what changes?
A data engineer builds pipelines within one programme and delivers working code. An architect decides what the platform should be and why, sets standards many teams follow, works with the CIO, CDO, risk and compliance, and produces architecture documents, decision records, roadmaps and operating models.
Q4.How would you modernise a Teradata + SAS + Oracle estate with 400 reports?
Start with the business goals and a current-state assessment (systems, flows, report usage, pain points). Inventory and rationalise: retire unused reports and dead code. Define the target architecture and principles, choose the platform with a weighted scoring matrix, and record ADRs. Migrate in waves by domain, with a shared conversion and reconciliation framework, parallel runs and sign-off. Put governance in place early, and present a 12–36 month roadmap with quick wins, dependencies and risks.
Q5.Lakehouse, warehouse or data mesh: how do you decide?
They answer different questions. Warehouse vs lakehouse is a platform choice: decide by workloads (BI vs ML vs streaming), data types, skills, cost, regulation, existing investment, lock-in and AI plans. Mesh is an operating model (domain ownership with federated governance) that suits large organisations with capable domain teams, and it can run on either platform.
Q6.How would you design a single customer view (MDM) for a bank?
Define the customer domain and a canonical model, pick an MDM style (registry, consolidation, coexistence or centralised) based on how much source systems must change, build matching and survivorship rules (deterministic plus fuzzy matching on name, DOB, ID documents), assign a golden ID with cross-references to source IDs, and govern it with data owners, stewards and DQ scorecards. Publish it as a data product consumed by CRM, risk and analytics.
Q7.What makes data "AI-ready", and how would you build a GenAI assistant over internal documents?
AI-ready data is discoverable, well described (catalog, semantic layer), quality-checked, governed and accessible through APIs. For a document assistant use RAG: chunk documents → embed → store in a vector database → retrieve → LLM. Enforce access control at retrieval time so users only see what they are entitled to, mask PII, ground answers with citations to reduce hallucinations, and evaluate and monitor responses under model-risk governance.

20. Behavioral Questions

Answer with STAR: Situation, Task, Action, Result. Quantify results where you can.

Q1.Tell me about a pipeline failure in production and how you handled it.
Cover detection (how you found out), immediate mitigation, root cause, the permanent fix, and what monitoring or tests you added so it would not recur.
Q2.Describe a time you improved performance or reduced cost.
Give the baseline and the result in numbers (runtime, cost per run, data scanned), and explain the technical change that caused it.
Q3.How do you handle conflicting requests from stakeholders?
Clarify the underlying business goal, make trade-offs explicit (time, cost, data quality), agree on priorities with whoever owns them, and communicate the decision.
Q4.Tell me about a time you worked with bad or ambiguous data.
Explain how you profiled it, what assumptions you validated with source owners, how you quarantined or flagged bad records, and how you documented the rules.
Q5.What does a Databricks architect do, compared with a data engineer?
A data engineer builds pipelines within the platform's standards. A Databricks architect designs the platform and solutions on it: workspace, network and Unity Catalog design, security and governance, engineering standards (repo layout, bundles, CI/CD), performance and cost, migrations, and ML/GenAI foundations, while guiding teams through design reviews and ADRs. An enterprise data architect works one level up, across all platforms.