Data Engineer Top 100 Interview Questions
100 data engineer interview questions with structured answers, comparison tables, flow diagrams, worked calculations and runnable examples. Covers SQL, data modeling, ingestion, storage, distributed processing, streaming, Python, data quality, governance and system design, from fundamentals to production operations.
Questions 81-100 of 100
Q81.A dashboard total is wrong even though every job succeeded. How would you debug it?
I would trace the incorrect business result backward through its lineage and find the first boundary where meaning or totals diverge. Green job status only confirms that execution completed.
- Reproduce the reported result using the same filters, timezone, metric definition, dataset version, and reporting interval as the affected consumer.
- Compare control totals and representative keys at successive stages: presentation, serving model, transformed data, raw ingestion, and authoritative source.
- Investigate the first divergence for missing updates, duplicate joins, partial arrivals, incorrect filters, currency mixing, or changed business logic.
- Repair the smallest correct scope, reconcile dependent outputs, communicate impact, and add a targeted check that would catch this failure earlier.
flowchart TD A["Reproduce incorrect business result"] B["Trace lineage and compare controls"] C{"First divergence located?"} D["Inspect transformation and input meaning"] E["Move to preceding boundary"] F["Repair and validate dependencies"] G["Add targeted detection"] A --> B B --> C C -->|yes| D C -->|no| E E --> B D --> F F --> GTrade-offs:
- A quick downstream patch can restore a report but must not hide a source or transformation defect that will recur.
- Rebuilding all history is costly and can introduce new discrepancies; determine the affected interval and consumers first.
Example
A daily revenue dashboard is 5% too high after a dimension update.
- Raw order totals still match the source.
- The first increase appears after joining product versions.
- Correct the effective-date join so each order matches one applicable version.
- Rebuild affected outputs and add a fact-row preservation check.
Q82.How would you deploy a pipeline change safely?
I would release versioned code and configuration with explicit data compatibility and validation gates. A deployment is successful only when the resulting datasets remain correct and usable.
- Version transformation logic, configuration, dependency definitions, and schema expectations, and review compatibility with retained data and downstream consumers.
- Run focused logic, contract, integration, and reconciliation checks on representative inputs, including historical and failure cases relevant to the change.
- Build staged or parallel outputs where practical, compare business results and resource behavior, and publish through a controlled switch or bounded rollout.
- Monitor freshness, quality, and cost after release, with a rollback plan that addresses both executable code and any already-published incompatible data.
flowchart TD A["Version and review change"] B["Run logic and contract checks"] C["Build staged outputs"] D{"Release criteria met?"} E["Publish controlled release"] F["Monitor consumer outcomes"] G["Investigate before release"] A --> B B --> C C --> D D -->|yes| E D -->|no| G E --> FTrade-offs:
- Parallel processing provides strong comparison evidence but temporarily increases compute and storage cost.
- Rolling back code does not automatically repair data written by the newer version; include data recovery in the plan.
Q83.How do data lineage, a data catalog, and business metadata differ?
Lineage describes how data flows and changes. A catalog helps people discover and manage datasets, while business metadata explains what the data means and who is responsible for it.
Lineage Catalog Business metadata Asks: where did this value come from? Asks: what datasets are available? Asks: how should this data be interpreted? Sources, transformations, dependencies Searchable assets and technical metadata Definitions, owners, usage rules When to use which:
- Use lineage to investigate incidents, assess the impact of changing a field, and identify downstream outputs that need correction or deletion propagation.
- Use a catalog to make trustworthy datasets discoverable, including their schema, ownership, freshness, quality status, and access process.
- Use business metadata to prevent different teams from interpreting the same column or metric differently, especially for units, time boundaries, and inclusion rules.
Automated technical lineage may miss manual exports or dynamic behavior. Maintain coverage deliberately and verify that documentation corresponds to the deployed transformation version.
Q84.What privacy and retention controls belong in a data platform?
Privacy controls should limit unnecessary exposure throughout ingestion, transformation, serving, and recovery. Retaining data because storage is inexpensive can create avoidable operational and access obligations.
- Minimization: collect only necessary fields and reduce or remove sensitive detail before it reaches broad analytical datasets when the use case permits.
- Access and representation: restrict sensitive columns and raw zones, use approved masking or tokenization, and protect reidentification mappings separately from ordinary consumer access.
- Lifecycle: define retention and deletion behavior for primary tables, derived datasets, caches, exports, quarantine, and backups, with explicit handling during restoration.
- Auditability: record access and deletion activity without copying secrets or unnecessary personal data into logs, and verify that controls remain effective after changes.
Pseudonymized identifiers can still link records to people. Treat them according to the actual reidentification risk rather than assuming a replacement identifier makes data anonymous.
Q85.How would you aggregate a large CSV file in Python without loading every row into memory?
I would parse the file incrementally and retain only the aggregation state. A CSV parser is necessary because quoted commas and newlines make manual string splitting unreliable.
- Input: read from a text stream with an explicit encoding and appropriate newline handling, validate the header, and define how malformed rows should fail or be quarantined.
- Computation: update a dictionary of totals while iterating through records rather than converting the entire reader to a list.
- Numeric policy: use an agreed decimal representation for exact decimal amounts and reject non-finite values instead of allowing them to contaminate totals.
- Memory: usage depends on the number of distinct grouping keys, so very high cardinality may require external partitioning or a distributed aggregation.
The small in-memory stream below demonstrates the same iteration pattern used with an open file.
Example
This example correctly parses a merchant name containing a comma and aggregates exact decimal amounts.
import csv from decimal import Decimal from io import StringIO def totals_by_merchant(stream): reader = csv.DictReader(stream) if reader.fieldnames != ['merchant', 'amount']: raise ValueError('unexpected columns') totals = {} for row in reader: if None in row or any(value is None for value in row.values()): raise ValueError('wrong field count') merchant = row['merchant'].strip() amount = Decimal(row['amount']) if not merchant or not amount.is_finite(): raise ValueError('invalid merchant or amount') totals[merchant] = totals.get(merchant, Decimal('0')) + amount return totals source = StringIO('merchant,amount\n"North, Shop",10.25\nSouth,7.00\n"North, Shop",5.25\n') totals = totals_by_merchant(source) print([(name, str(total)) for name, total in sorted(totals.items())]) # Expected output: [('North, Shop', '15.50'), ('South', '7.00')]Q86.How would you flatten nested order records while preserving their parent identifiers?
I would emit one row per child item and copy the required parent identity onto each emitted row. The output grain must be defined before flattening nested structures.
- Mapping: identify which parent fields belong on every child record and which repeated collections should remain separate to avoid accidental Cartesian multiplication.
- Identity: preserve a source child identifier when available; a list position is suitable only when the source contract makes that position stable enough for the intended use.
- Empty children: define whether an order with no items emits no line rows or an explicit parent-only record in another dataset.
- Validation: check required fields and item types, and stream output through a generator when the input can be large.
Flattening changes representation, not business meaning. Keep an order-level dataset when consumers also need orders without any child rows.
Example
For this example, line positions define the child identifiers within each immutable input order.
def flatten_orders(orders): for order in orders: for line_number, item in enumerate(order['items'], 1): quantity = item['quantity'] if type(quantity) is not int or quantity <= 0: raise ValueError('quantity must be a positive integer') yield { 'order_id': order['order_id'], 'line_number': line_number, 'sku': item['sku'], 'quantity': quantity, } orders = [ {'order_id': 10, 'items': [ {'sku': 'A', 'quantity': 2}, {'sku': 'B', 'quantity': 1} ]}, {'order_id': 11, 'items': []}, ] print([(r['order_id'], r['line_number'], r['sku'], r['quantity']) for r in flatten_orders(orders)]) # Expected output: [(10, 1, 'A', 2), (10, 2, 'B', 1)]Q87.How would you separate valid records from rejected records in Python?
I would implement explicit validation rules and retain a clear rejection reason for every failed record. Missing fields and invalid values should not disappear through broad exception handling.
- Contract: define accepted field types and business constraints, including whether empty identifiers or zero quantities are meaningful for this dataset.
- Type checks: account for language details such as booleans being integer subclasses; use the intended type rule rather than accepting values accidentally.
- Outputs: route accepted records and restricted rejection evidence separately, retaining source position or identity for later repair and reconciliation.
- Scale: the sample returns small lists for readability; a large pipeline should emit records to bounded buffers or durable sinks instead of retaining all outcomes.
Keep input count equal to accepted plus rejected count, and define whether the failure rate should block publication.
Example
This example rejects a Boolean quantity and a missing order identifier with explicit reasons.
def validate(record): if not isinstance(record, dict): return 'record must be an object' identifier = record.get('order_id') if not isinstance(identifier, str) or not identifier.strip(): return 'order_id is required' quantity = record.get('quantity') if type(quantity) is not int or quantity <= 0: return 'quantity must be a positive integer' return None def split_records(records): accepted, rejected = [], [] for position, record in enumerate(records, 1): reason = validate(record) if reason is None: accepted.append(record) else: rejected.append((position, reason)) return accepted, rejected accepted, rejected = split_records([ {'order_id': 'A1', 'quantity': 2}, {'order_id': 'A2', 'quantity': True}, {'quantity': 3}, ]) print([r['order_id'] for r in accepted]) print(rejected) # Expected output: # ['A1'] # [(2, 'quantity must be a positive integer'), (3, 'order_id is required')]Q88.How would you merge several already-sorted event streams in Python?
I would use a heap-based merge that keeps the next candidate from each input stream. This avoids concatenating all records and sorting the combined dataset from scratch.
- Precondition: every input must already be ordered by the same complete comparison key, including any tie-breaker needed for deterministic output.
- Algorithm: select the smallest available candidate, emit it, and replace it with the next item from that candidate’s input stream.
- Complexity: for N total records across k streams, a typical heap merge takes
O(N log k)time andO(k)merge state, excluding upstream buffers. - Semantics: merging preserves records, including duplicates; deduplication or reconciliation is a separate requirement that needs a defined identity rule.
Normalize timestamp interpretation before merging. Differently formatted local-time strings are not necessarily ordered by their true event instants.
Example
Each tuple contains an event-time position followed by a stable event identifier, and each input is sorted by both fields.
from heapq import merge left = iter([(1, 'a'), (4, 'd')]) right = iter([(2, 'b'), (4, 'e')]) for event_time, event_id in merge(left, right): print(event_time, event_id) # Expected output: # 1 a # 2 b # 4 d # 4 eQ89.How would you process an iterable in bounded batches, including its final partial batch?
I would accumulate at most the requested number of records, yield the completed batch, and emit any remainder after input is exhausted. A generator keeps the producer compatible with streaming input.
- Validation: reject non-integer or nonpositive batch sizes before processing, including Boolean values if the interface requires an actual integer count.
- Memory: retain one bounded batch instead of materializing the whole iterable; downstream consumers must also avoid collecting every yielded batch unnecessarily.
- Completeness: emit the final partial batch and handle empty input without inventing an empty write operation.
- Delivery: keep extraction batching separate from commit and retry policy; yielding a batch does not prove the destination durably stored it.
Choose batch size using payload bytes, service limits, latency, and recovery cost as well as record count.
Example
This generator accepts any iterable and emits a final batch containing the remaining record.
def batches(records, size): if type(size) is not int or size <= 0: raise ValueError('size must be a positive integer') batch = [] for record in records: batch.append(record) if len(batch) == size: yield batch batch = [] if batch: yield batch for batch in batches(iter(range(7)), 3): print(batch) # Expected output: # [0, 1, 2] # [3, 4, 5] # [6]Q90.How would you detect inserted, updated, and deleted records between two snapshots in Python?
I would index complete snapshots by stable business key, then compare their key sets and corresponding values. A missing row represents a deletion only when both snapshots have the same complete scope.
- Identity: reject duplicate or missing keys before comparison, because silently overwriting duplicates can hide source defects and produce false changes.
- Classification: keys only in the new snapshot are inserts, keys only in the old snapshot are deletes, and unequal records under shared keys are updates.
- Equality: define field normalization, ignored metadata, NULL treatment, and numeric comparison rules before deciding whether two records differ.
- Scale: dictionary comparison uses memory proportional to both snapshots; sorting emitted keys adds ordering cost, while large inputs may need an external merge.
This comparison identifies net differences between snapshots, not intermediate updates that occurred and were later reversed.
Example
This complete example uses full dictionary equality and returns changes in deterministic identifier order.
def index_records(records): result = {} for record in records: key = record.get('id') if not isinstance(key, str) or not key or key in result: raise ValueError('identifiers must be unique nonempty strings') result[key] = record return result def snapshot_changes(before, after): old, new = index_records(before), index_records(after) for key in sorted(old.keys() | new.keys()): if key not in old: yield ('insert', key) elif key not in new: yield ('delete', key) elif old[key] != new[key]: yield ('update', key) before = [{'id': 'A', 'city': 'Pune'}, {'id': 'B', 'city': 'Delhi'}] after = [{'id': 'B', 'city': 'Chennai'}, {'id': 'C', 'city': 'Pune'}] print(list(snapshot_changes(before, after))) # Expected output: [('delete', 'A'), ('update', 'B'), ('insert', 'C')]Q91.How would you estimate storage needs for an event pipeline?
I would estimate retained data volume from event rate, encoded event size, retention, compression, and physical copies, then add measured operational overhead. Raw payload size is only the starting point.
- Base volume:
raw bytes = events per day × average bytes per event × retained days; use representative encoded records rather than an optimistic field-only estimate. - Compression: divide by the measured compression ratio, defined here as uncompressed size divided by compressed size.
- Copies: multiply by the number of physical copies that must be provisioned, avoiding double-counting replication already included in a managed storage estimate.
- Overhead: allow for indexes, metadata, checkpoints, intermediate outputs, compaction overlap, growth, and recovery headroom.
State whether units are decimal GB and TB or binary GiB and TiB. Also estimate requests and throughput separately from storage capacity.
Example
Assume 50 million events daily, 1,000 bytes per event, 30 days retained, 3:1 compression, and two provisioned copies.
- Daily raw size:
50,000,000 × 1,000 = 50,000,000,000 bytes = 50 GB. - Retained raw size:
50 GB × 30 = 1,500 GB. - Compressed storage with two copies:
1,500 / 3 × 2 = 1,000 GB. - Adding a stated 20% allowance gives
1,200 GB = 1.2 decimal TB.
- Base volume:
Q92.How would you estimate the time required to drain a streaming backlog?
I would divide the backlog by the sustainable excess processing rate after accounting for new arrivals. Using total processing throughput alone underestimates recovery time while traffic continues.
- Formula:
drain time = backlog / (processing rate - arrival rate), with all rates measured in compatible records or bytes per unit time. - Feasibility: processing must exceed arrival rate; equal rates preserve the backlog, while a lower processing rate makes it grow.
- Measurement: use sustained successful output throughput rather than theoretical worker capacity, and include throttling, retries, state access, and skew.
- Planning: verify that source retention, deadlines, and downstream capacity support the calculated recovery period, then include headroom for variability.
For changing traffic, estimate across time intervals or simulate the expected rate profile. One average can hide a peak that removes all spare capacity.
Example
A pipeline has 1,800,000 queued events, receives 900 per second, and sustainably completes 1,200 per second.
- Spare capacity is
1,200 - 900 = 300 events per second. - Drain time is
1,800,000 / 300 = 6,000 seconds. - That equals
100 minutes, assuming both rates remain stable. - Confirm that the oldest queued events remain within retention throughout recovery.
- Formula:
Q93.How would you reduce a data platform’s cost without weakening its delivery requirements?
I would attribute spending to useful workloads and remove avoidable work while measuring correctness and service targets. The cheapest isolated job is not necessarily the cheapest dependable platform.
- Break down cost by storage, compute, scan volume, requests, network transfer, idle capacity, and repeated failures, identifying the main consumers.
- Find repeated full scans, unnecessary columns, inefficient layouts, tiny files, unused outputs, excessive refresh frequency, and resources left running without demand.
- Apply targeted changes such as incremental processing, better pruning, workload scheduling, retention cleanup, or suitable materialization of repeatedly computed results.
- Compare cost per useful delivered unit alongside freshness, quality, query latency, and recovery performance before and after the change.
flowchart TD A["Attribute workload costs"] B["Locate avoidable work"] C["Apply measured optimization"] D{"Service targets still met?"} E["Keep change and monitor"] F["Revise or roll back"] A --> B B --> C C --> D D -->|yes| E D -->|no| FTrade-offs:
- Precomputed results reduce repeated query work but add refresh complexity and can become stale.
- Shorter retention reduces storage only if recovery, historical analysis, and agreed lifecycle requirements remain satisfied.
Example
A report scans all history hourly even though only the newest day usually changes.
- Measure the scan and compute cost attributable to this refresh.
- Process affected partitions while retaining a correction path for late historical changes.
- Reconcile against periodic complete calculations.
- Keep the change only if savings persist without missed updates or stale reports.
Q94.How would you secure access to data pipelines and their destinations?
I would authenticate each workload with a distinct identity and grant only the permissions needed for its responsibilities. Encryption and access control protect different parts of the threat model.
- Least privilege: separate ingestion, transformation, serving, and administration identities, limiting source reads, destination writes, and sensitive field access appropriately.
- Credentials: use managed or short-lived credentials where available, protect secrets outside code and logs, and rotate or revoke access through a controlled process.
- Encryption: protect transport and stored data, manage encryption-key access separately where appropriate, and verify that backups and temporary outputs receive equivalent protection.
- Network and audit: restrict unnecessary connectivity, record meaningful access events, and review privileges as datasets, ownership, and deployment environments change.
Apply controls to intermediate files and debugging outputs too. A carefully protected warehouse does not compensate for unrestricted raw exports produced earlier in the pipeline.
Q95.What do RPO and RTO mean for disaster recovery?
Recovery point objective, or RPO, defines the maximum acceptable data-loss interval. Recovery time objective, or RTO, defines the target duration for restoring the required service after disruption.
RPO RTO How much recent work can be lost? How long can service be unavailable? Shaped by replication, backups and replay history Shaped by restore speed, dependencies and validation When to use which:
- Use RPO to decide how current recoverable data must be, including whether retained source history can reconstruct changes after the latest backup.
- Use RTO to design and test restoration procedures, access recovery, capacity provisioning, dependency sequencing, and the checks needed before reopening service.
- Evaluate both together for each critical dataset, because fast restoration of stale data can meet one target while violating the other.
These are objectives, not guarantees created by writing them down. Measure achieved loss and recovery time through realistic restore exercises.
Example
A disruption occurs at 14:00. The latest recoverable state is from 13:50, and the required service is restored at 14:40.
- The observed data-loss interval is 10 minutes, assuming no later changes can be replayed.
- The observed recovery duration is 40 minutes.
- These satisfy targets of RPO 15 minutes and RTO 60 minutes.
- Validate data and dependencies before counting the service as restored.
Q96.How would you design a daily sales analytics pipeline end to end?
I would define the sales metrics and publication deadline first, then build a traceable flow from source changes to validated reporting tables. Order state and cash movement should not be confused.
- Agree on business grain, currencies, timezones, refund treatment, source ownership, volume, retention, and the deadline for a complete daily dataset.
- Ingest source snapshots or changes into a controlled replayable area, preserving identifiers, source positions, schema versions, and deletion evidence.
- Build conformed dimensions and separate process facts, apply tested transformations, and reconcile quantities and amounts before publishing the serving version.
- Provide governed analytical access with freshness and quality monitoring, documented lineage, bounded backfills, and tested recovery for missed or corrected source data.
flowchart TD A["Operational source changes"] B["Replayable controlled ingestion"] C["Validated dimensions and facts"] D{"Reconciliation passes?"} E["Publish analytical tables"] F["Serve governed reports"] G["Hold and investigate"] A --> B B --> C C --> D D -->|yes| E D -->|no| G E --> FTrade-offs:
- A scheduled batch is often sufficient for daily reporting, while more frequent updates add value only when consumers need them.
- Retained source history supports corrections but increases governance and lifecycle management responsibilities.
Example
A daily report must be available by 07:00 in the business timezone.
- Confirm when all required sources normally finish publishing the prior day.
- Validate that arrivals are complete before closing the reporting interval.
- Publish reconciled sales and refund facts through one serving-version change.
- Route later corrections through a documented revision process so consumers can identify updated totals.
Q97.How would you design a near-real-time clickstream analytics pipeline?
I would define the required event-time metrics and acceptable delay, then design for bursts, replay, duplicates, and late arrivals. Click arrival speed alone does not establish analytical correctness.
- Define event identifiers, user or session keys, timestamps, schema contracts, consent-related controls, expected peak rate, and the required metric freshness.
- Ingest into a durable partitioned log with suitable retention and routing, and preserve a governed raw history for replay and validation.
- Validate and deduplicate events, apply bounded event-time windows or sessions, and publish results through a sink that supports the chosen update semantics.
- Monitor source-to-result delay, state growth, rejection, late records, and consumer lag, with capacity headroom and an offline reconciliation and correction path.
flowchart TD A["Tracked events"] B["Durable partitioned log"] C["Validate and deduplicate"] D["Bounded event time aggregation"] E["Update analytical serving store"] F["Governed replay history"] G["Reconcile and correct results"] A --> B B --> C C --> D D --> E B --> F F --> G G --> ETrade-offs:
- Longer lateness horizons improve completeness for delayed events but increase state and delay finalization.
- Partitioning by session supports local ordering while popular keys and uneven traffic still require capacity analysis.
Example
A dashboard shows five-minute activity totals updated every minute.
- Use overlapping five-minute event-time windows with a one-minute step.
- Deduplicate by stable event identifier within the defined replay policy.
- Mark early results provisional and handle permitted late updates.
- Compare finalized results with retained raw events and publish corrections when required.
Q98.How would you migrate a large analytical dataset with minimal disruption?
I would combine a validated historical copy with a controlled change catch-up and serving cutover. Moving bytes is only part of migrating schemas, permissions, and consumer behavior.
- Inventory datasets, dependencies, access policies, query semantics, precision, timezones, service targets, and the rollback boundary before transferring data.
- Copy history through consistent bounded snapshots while retaining subsequent changes, and validate partition counts, keys, amounts, and representative queries.
- Apply ongoing changes until the new system reaches an agreed consistent boundary, then test performance and permissions with realistic consumer workloads.
- Switch reads through a controlled cutover, prevent divergent authoritative writes, monitor results, and retain the old recovery path until acceptance criteria are met.
flowchart TD A["Inventory contracts and dependencies"] B["Copy consistent history"] C["Retain and apply later changes"] D["Validate data and consumer queries"] E{"Cutover criteria met?"} F["Switch serving and monitor"] G["Continue repair and catchup"] A --> B B --> C C --> D D --> E E -->|yes| F E -->|no| G G --> CTrade-offs:
- Parallel environments reduce cutover risk but temporarily increase cost and require clear authority for writes.
- A reversible read switch is useful only if data produced after cutover can also be recovered or reconciled during rollback.
Example
A warehouse migration begins while new orders continue arriving.
- Copy a consistent historical boundary and retain later order changes.
- Catch up the destination and reconcile at a known position.
- Compare important report results and access behavior before switching readers.
- Keep the previous environment available under a defined rollback and final-retirement plan.
Q99.How should you explain a data engineering project you personally worked on?
Use a real project to show how requirements shaped your technical decisions and what you personally owned. A clear explanation connects architecture to measurable consumer outcomes.
- Describe the business problem, data sources, consumers, scale, and delivery requirements, distinguishing measured facts from estimates.
- Explain your responsibility and the architecture, including ingestion, modeling, transformations, publication, and important security or recovery decisions.
- Discuss one meaningful trade-off and the alternatives considered, using evidence about correctness, freshness, performance, or operating cost.
- Describe validation, a difficult failure or edge case, and how you detected and resolved it without hiding the limitations.
- State the actual outcome and what you would improve next, giving numbers only when you can explain how they were measured.
What the interviewer is listening for: ownership, sound data reasoning, operational awareness, clear communication, and honest attribution of team contributions.
Q100.How should you discuss a pipeline incident or a disagreement about data correctness?
Describe a real situation and show how you protected consumers, established evidence, and helped the team reach a sound resolution. The learning matters more than presenting yourself as faultless.
- Explain the context, affected consumers, symptoms, and uncertainty, including whether the issue involved availability, freshness, incorrect meaning, or incomplete data.
- State your responsibility and the immediate containment or communication steps, distinguishing confirmed facts from early hypotheses.
- Describe how you traced evidence, compared competing explanations, and chose a repair or experiment with clear acceptance criteria.
- Explain the result, validation, and any correction of downstream outputs, giving credit to collaborators and acknowledging mistakes directly.
- Describe the preventive change, such as a contract, reconciliation check, runbook, or ownership improvement, and how its usefulness was assessed.
What the interviewer is listening for: calm judgment, accountability, constructive disagreement, technical investigation, and follow-through after recovery.