Scenarios
Longer problems, like those in senior system design interviews. A strong answer estimates with numbers first, names the mechanism, then recommends a fix and says what it costs.
1Two dashboards show Q3 revenue of $4.20M and $4.79M, and both pass all their data tests. How do you find the cause and prevent it?Show the answer
Mechanism first
Nothing can say which number is "true", so differences come from meaning, not code. The gap is 4.79 ÷ 4.20, about 14%.
Diagnose by the four primitives
- Grain: compare each source table's declared grain; look for subtotal rows, or rows repeated once per campaign touch.
- Identity: do both dashboards count the same entity (orders, or customers)?
- Time: "as was" or "as is" dimension versions, and which time zone.
- Boundary: are they reading different copies of the same attribute?
A fast test: reconcile row counts and distinct order numbers at the lowest grain both share, then bisect by month.
Fix
Declare the grain of every table, give each metric one owner in a semantic layer, and run a daily job reconciling the two totals.
Trade-off and warning
Governance becomes a bottleneck. And an unexplained difference signals undefined meaning, not a bug to patch.
Read moreA layer with no oracleThe four primitivesTwo named trapsThe semantic layer
2Design the customer dimension for a retailer with 5 million customers, address changes, a loyalty tier that changes monthly, and a legal requirement to reproduce last year's reports exactly.Show the answer
The requirement drives the type
Reproducible reports need "as was" values for every attribute used in reports. Choose a type per attribute.
Per attribute
- Email: type 1, overwrite; no history needed.
- Region or territory: type 2, with a surrogate key, effective dates and a current flag.
- Loyalty tier: it changes monthly for everyone, so type 2 would add about 5,000,000 × 12 = 60 million rows a year. Use a mini-dimension (type 4) of the few tier-and-band combinations, referenced from the fact table.
Late data
Look up versions by effective-date range, with a policy for inferred members and a check that they expire.
Keys
Surrogate keys. If loads must run in parallel, use a hash of (source, natural key), knowing it bakes in trust in the natural key.
Risks
Late corrections to the dimension rewrite history in proportion to the facts they touch; type 6 would make backfills proportional to versions; and nothing ever deletes old versions, so plan retention.
Read moreThe slowly changing dimension typesType 4: a mini-dimensionLate arrivals
3Finance wants each customer's balance for every day of the last 3 years, for 2 million accounts, answered in under a second. What do you build?Show the answer
Estimate
Choose
Balances are semi-additive stocks, so a periodic snapshot is the right fact type. Computing from events instead needs a running sum over each account's whole history, expensive per query but cheap to compute once. So precompute: one new day per night (about 2 million rows), stored in columnar form sorted by (account, date). Balances change rarely, so run-length encoding compresses it well.
Rules to enforce
Never sum across days; sum across accounts only within one date; for a period, use the last value or the average. A semantic layer should refuse to sum this measure over time.
Trade-offs
Storage grows with accounts × days, and late events force recomputing every later snapshot row from the date they change, so keep events as the source of truth.
4Sales wants revenue by rep, but many large deals have two or three reps, and the total by rep exceeds the company's revenue. Fix it, and explain what is and is not correct afterwards.Show the answer
Diagnose
Joining facts to a many-to-many relationship repeats each fact once per rep: a $1,000 deal with two reps sums to $2,000.
Fix
A bridge table keyed by a rep-group key, with weights that sum to 1 within each group (for example 0.6 and 0.4). Revenue by rep = SUM(amount × weight), which adds up to company revenue.
What is correct
The sum over reps now equals the total, but each rep's share is only as right as the agreed policy, which no data can validate. Offer a second, clearly named "influenced revenue" measure, correct per rep but never to be summed.
Alternatives
An array of reps on each fact moves the trap to whenever it is unnested; a group key alone loses per-rep queries.
Governance
The allocation policy needs an owner and a version, because changing it restates every historical rep number.
Read moreThe bridge table and the weighting factorTwo honest options and one dishonest oneTwo other escapes
5After an acquisition, three source systems hold overlapping customers with conflicting data, and compliance needs an audit trail of what each system said. Do you use Data Vault?Show the answer
Test the fit
The sources are many, contested and changing, and the auditor asks what each source said and when. That fits Data Vault.
Design
Hubs of hashed business keys (source plus key), a link from customer to order, and a satellite per source with load timestamps and the record's source. Deterministic hashes make loading independent of order.
Do not skip the presentation layer
Build a star schema or wide marts on top; the Vault is an addition, not a replacement. Use entity resolution to link records across systems, and store each resolved person with their own surrogate key and version history, since a merge restates historical counts.
Costs
Complexity for readers, nothing that deletes old data (plan retention), and hashes that bake in trust in the business keys. With one source and one team, it is pure overhead. Whether cheap columnar compute makes the Vault a sensible default is still unsettled.
Read moreData VaultFour properties that followEntity resolution
6Marketing, finance and support each report a different number of 'active customers'. Propose a fix that survives growth to 40 teams.Show the answer
Diagnose
The metric is a computation with unstated edge cases (refunds, test accounts, time zone, partial periods), and each team re-derives it.
Fix
A semantic layer with one definition per metric name, an owner, and code review for changes, so meaning can be diffed. Different meanings get different names, such as engaged_customers. Count resolved people where possible.
Why it scales
With 40 teams, reconciling pairwise is 40 × 39 / 2 = 780 pairs; shared definitions need 40 agreements.
Trade-offs
The layer is a query compiler, so predicate pushdown must work or performance suffers, and it becomes the bottleneck for disputes over definitions. A federated model only moves that cost into contracts between domains.
Roll out
Start with the ten metrics executives use, publish them first, and retire shadow definitions with a deprecation date.
Read moreThe semantic layerThe honest costsWhy conformance is a coordination problem
7A pipeline bug corrupted revenue figures for 45 days, and the source keeps its files for only 30. How do you redesign so this becomes recoverable, and what will it cost?Show the answer
Principle
Materialize at the boundaries where reversibility and trust change. Parsing is mechanical, deduplication loses information, and business logic is opinionated.
Design
Three layers: raw (byte-for-byte, with arrival time), clean (parsed and deduplicated), and business (metrics). Publish guarantees at each boundary (schema, freshness, uniqueness, null policy, grain) and name an owner. A logic bug then means rerunning from the clean layer.
Costs
Roughly 3 times the storage, and latency that is the sum of the hops, for example 10 + 15 + 20 = 45 minutes.
The exception
If the upstream is an immutable log with long retention, the raw copy only adds retention depth and decoupling.
Recovering now
Ask the provider for a re-export, or rebuild from any copy of the business layer's inputs. Data that no longer exists anywhere cannot be recomputed. And layers without published guarantees are three copies with no safety.
8A product team wants to answer retention questions nobody has thought of yet. Should the whole platform be event-sourced?Show the answer
Weigh event sourcing
It keeps every future question open, since you can build new projections retroactively. But it costs snapshots (replay time keeps growing), event schemas that are permanent (versioned only by translating on read), no canonical current state, and handling of retractions for corrections.
For analytics
An activity table, one row per activity per entity, makes temporal questions such as "second order within 7 days" into window queries, without moving the operational system to event sourcing.
Recommend
Keep operational tables ordinary, feed an activity table from change events, and add a semantic layer: both event approaches push meaning into queries, which then get re-derived by every consumer.
Limits and a decision rule
An activity table handles set and allocation questions poorly, and needs engine support for as-of and interval joins. Decide by counting how many questions in the last six months needed history the current model could not provide.
Read moreEvent sourcingActivity schemaBoth push meaning into the query