Skip to content
About
Main content

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.

Try each one before you open the answer.
1A report takes 3 hours and must run in under a minute. Where do you look?Show the answer

Find the peak

Multiply row counts along the plan and find where they peak. The usual cause is a or an unnest that runs before a filter or an .

Check the order of work

Filters should sit below joins, and aggregates should be reduced to the join key's grain before joining: a join that fans out rows is a granularity mismatch.

Count enforcers

How many distinct sort orders and does the plan add?

Recommend

Reduce rows early, then join; verify with EXPLAIN ANALYZE.

Risk

The 's estimates may be wrong because correlated predicates were .

Read moreThe five questions behind any operator's costFilter and projectionRequires, provides and enforcers

2A table of 2 billion orders, 200 bytes each, joins a 500 MB dimension table on a cluster of 200 executors with 16 GB of memory each. Broadcast or shuffle?Show the answer

Network

Broadcast moves 500 MB × 200 = 100 GB; shuffling moves about 400 GB. The size ratio, 800, exceeds P = 200, so .

Memory

Broadcast means 100 GB of copies across the cluster and 200 hash-table builds, and 500 MB is far above typical broadcast thresholds of tens of MB.

A bonus

Broadcasting keeps the orders table's existing partitioning, which can save a later shuffle.

Recommend

Broadcast if each has room in its 16 GB and no driver becomes a bottleneck; otherwise shuffle with a runtime filter.

Failure mode

A central driver collecting the whole table before broadcasting it.

Read moreBroadcast, shuffle, and the partitioning you haveRuntime filters

3A join job has a single straggler task that runs for 2 hours after all the others finish. Diagnose and fix.Show the answer

Diagnose

Check the frequency distribution of join keys, and the fraction of keys. With Zipf-distributed keys, the top key carries about 7% of rows, which however many workers you add.

Fix, in order

  1. Filter NULL keys out before the shuffle: free.
  2. Split the : let the engine split skewed at run time, or salt it with s copies of the other side if the hot keys are stable.
  3. Use sampled .

When nothing helps

If the hot key is hot on both sides, the output itself is huge; pre-aggregate one side.

Read moreSkew: the assumption of uniformity, priced

4An analyst's report that uses NOT IN suddenly returns no rows. What happened, and what should the platform do?Show the answer

Diagnose

A NULL entered the subquery's results. Under , x NOT IN (…, NULL) is UNKNOWN for every row, so nothing passes.

Fix

Rewrite with NOT EXISTS, or filter NULLs out of the subquery.

Platform

Add a data-quality check on the column, and consider a lint rule against NOT IN on nullable columns. While there, also check for right-side conditions in WHERE on LEFT JOINs, and joins that fan out rows before a SUM.

Read moreThe join family

5Choose a join strategy for a 10 TB fact table and a 50 GB table, where the join condition is a range on time.Show the answer

Rule out

A hash join: the condition is a range, not an equality.

Check the shape

If it is "the latest row at or before t", use an operator.

Otherwise

A , or . Estimate the replication factor (average interval length ÷ bucket width), and check the distribution of interval lengths for a heavy tail. A merge needs memory only for the longest run of duplicates.

Caveat

There is no simple anchor for the output size, so test it on a sample.

Read moreRange and interval joinsAs-of joins

6With 16 GB of memory and 8 MB I/O buffers, one hash join's build side is 1.1 times memory and another's is 3 TB. What happens in each case?Show the answer

1.1 × memory

A only : a small penalty.

3 TB

A splits it into 3 TB ÷ 16 GB ≈ 188 partitions. The possible fan-out is 16 GB ÷ 8 MB = 2,048, so one level of partitioning is enough (the threshold for a second is about 32 TB), at the cost of 2 × (|R| + |S|) extra I/O.

The real danger

Neither case is a cliff. A single huge key would be, since it cannot be partitioned. A is the constant-memory alternative.

Read moreHybrid hash: a ramp, not a cliffWhen the build side does not fitOut-of-core: the threshold

7Should the platform build a runtime filter for every join?Show the answer

Estimate the leverage

About (row size ÷ roughly 1.2 bytes per key in the filter) × (1 − the fraction of rows that match). For 200-byte rows with 5% matching: about 167 × 0.95 ≈ 158×. For 8-byte rows with 90% matching: about 7 × 0.1 = 0.7, so no gain.

Cost

A barrier: the must wait for the build side to finish the filter.

Choose the filter

A min/max range when the data is clustered, an IN-list for a few keys, a otherwise.

Read moreSideways information passing

8A dashboard query has six window functions and an ORDER BY, and the plan shows six sorts. How do you reduce them?Show the answer

Count

Each distinct (PARTITION BY, ORDER BY) specification is a full sort.

Share orders

Reorder or unify the specifications so they share prefixes: one sort on (a, b) also (a). An equality predicate makes a column constant, so it drops out of the required order. Where input is already sorted on (a) and the requirement is (a, b), a needs memory only for the largest group, and streams.

Distinguish grouping from ordering

A window that only needs each partition's rows together does not need a global order.

Check frames

Default RANGE frames with ties cost more than ROWS. Sliding MAX or MIN costs O(log w) per row, and holistic functions over a frame cost O(w).

Longer term

A clustered or bucketed layout pays for the sort once, for every query, at write time, at the cost of constraining other queries on that table. And whenever specifications change, verify the results, since semantics may change too.

Read moreWindow functionsSort avoidance

9A report computing COUNT(DISTINCT user_id) GROUP BY page over 50 billion events fails with out-of-memory on one of 200 executors, each with 16 GB. Diagnose and fix.Show the answer

Diagnose

The function is holistic, so cannot shrink anything, and the group key is skewed. If the home page has 10% of events, that is 5 billion rows; at 8 bytes per user ID, 40 GB sent to one executor with 16 GB.

If about 1% error is acceptable

: 12 KB per page, mergeable, one shuffle, immune to , and its merges are exactly reproducible.

If it must be exact

Rewrite as SELECT page, COUNT(*) FROM (SELECT DISTINCT page, user_id …) GROUP BY page. The first shuffle is by the (page, user) pair, so the hot page spreads over all executors. It costs two shuffles but runs in parallel. Plain random would double-count users.

Note

Several distinct aggregates in one query mean several copies of the data on the wire.

Recommend

for dashboards, where the error has no meter and is paid silently by the reader; the exact two-shuffle plan for billing numbers.

Read moreTwo-phase aggregationThe parallel plan for exact COUNT DISTINCTWhat a sketch actually does

10A nightly SUM(amount) GROUP BY customer_id over 2 billion rows, with 40 million customers on 200 executors, runs slower with partial aggregation enabled than without. Why, and what do you change?Show the answer

Estimate

Each executor sees 10 million rows. With 40 million customers, it can expect about 40M × (1 − e^(−0.25)) ≈ 8.85 million distinct customers, so shrinks its data only about 1.13×. It pays a hash and a memory write per row, plus an 8.85-million-entry table, for a 12% smaller shuffle.

Fix

Turn partial aggregation off for this query, or enable an adaptive mode that samples the first tens of thousands of rows and abandons it when few rows hit existing groups. A plan-time estimate of distinct values is the least reliable statistic, so prefer sampling at run time.

Contrast

For GROUP BY country, the ratio is in the tens of thousands, and partial aggregation is a huge win.

Read moreThe core tension, as one ratioPartial aggregation

11Design the sort of a 20 TB table on 100 nodes with 64 GB of memory each and NVMe storage. What are the risks?Show the answer

Estimate

200 GB per node. With 32 GB of memory for the sort and 8 MB buffers, M² / B = 32 GB × 4,000 = 128 TB, so , and I/O is about 4N = 800 GB per node. At 3 GB/s that is under 5 minutes, so the node is likely CPU-bound if keys are strings with collation: use and sort compact (prefix, pointer) pairs.

Distributed shape

Range-partition on boundaries chosen from a random sample (a few hundred samples per partition), sort locally, and concatenate.

Risks

  • Biased samples from time-ordered files: sample at random, never the first rows.
  • A single key with more rows than one partition should hold defeats any boundaries.
  • Sampling is a barrier before any rows can be routed.
  • On object storage, larger buffers bring the third pass closer.

Read moreExternal merge sortChoosing the splittersThree failure modesNormalized keys

12A deduplication step uses a Bloom filter to drop events it has already seen. Finance reports that totals are 0.1% too low. Review the design.Show the answer

Diagnose

The filter has no false negatives but does have false positives. In deduplication, a false positive says "seen before" about a new event, so a real row is dropped, and nothing downstream checks. At 10 billion rows, 0.1% is 10 million lost rows, invisible to monitoring.

Repair

Use the filter only as a : "definitely new" emits immediately, "maybe seen" consults an exact store or an exact sort- or hash-based dedup. Or deduplicate exactly on a 128-bit digest (with 64 bits, at 10¹⁰ rows), using a sort-based dedup if the final stage does not fit in memory.

When approximate is fine

Best-effort telemetry, consumers that are idempotent anyway, and bounded-window filters that reset.

Monitor

Reconcile row counts against the source after every run.

Read moreThe same filter, the opposite consequenceUse 128 bits

13A pipeline joins on a key, aggregates on the same key, and orders the output by it. Choose between hash-based operators with shuffles and a sort-based plan.Show the answer

Count the requirements

A merge join needs order on the key, sort-based aggregation needs order (or grouping) on the key, and ORDER BY needs order on the key: three consumers of one order.

Decide

Sort once, merge-join, aggregate in one pass with constant memory, and the output is already ordered. A hash plan would build one for the join, another for the aggregation, then sort for ORDER BY. With only one consumer of the order, hashing would win.

Better still

If the table is clustered or bucketed on the key, the sort is free.

Risks

A hot key breaks range partitioning and hashing alike, and the sort needs N ≤ M² / B per node to finish in one merge pass.

Read moreAmortization across requirementsTwo ways to make equal things meet

14Your team wants a metric that is reproducible bit for bit across runs, but it is built from floating-point sums and p99 latency estimates. What do you do?Show the answer

Sums

Floating-point results depend on the order of additions. Use decimal or fixed-point types for money, compensated ( or Neumaier) summation, or sort before summing.

Percentiles

Choose the sketch by how it merges: merges are lossy and depend on the merge tree, so they are not reproducible; has a bounded error; exact quantiles come from sorting by (group, value) and reading positions.

State the trade-off

Exactness costs a sort; a sketch costs an error with no meter. t-digest is good for accuracy at p99 and p99.9, but not for reproducibility.

Read moreFloating-point summationMergeability is not uniform

15Estimate the cost of SELECT customer_id, SUM(amount) FROM orders GROUP BY customer_id ORDER BY customer_id over 2 billion rows and 40 million customers on 200 executors, where customer_id = 0 holds 7% of rows and 2% are NULL. Choose a plan.Show the answer

Estimate

The output is 40 million rows. Partial aggregation reduces data only about 1.13×, so the shuffle moves nearly all 2 billion rows × about 16 bytes (key and value) ≈ 32 GB. Each executor then owns 200,000 customers, which fits easily in memory (about 5 MB).

Plan

Make the shuffle a range partitioning on customer_id, and aggregate with a sort on each executor: the output is grouped and ordered at once, so ORDER BY costs nothing extra.

The hot key

customer_id = 0 is 140 million rows. SUM is distributive, so wherever partial aggregation applies it collapses that key to one row per executor and the skew is harmless; an adaptive engine keeps partial aggregation on when hot keys give a high hit rate.

NULLs

The 2% of NULL keys form one more group; decide whether the report should include it.

Read moreThe core tension, as one ratioSort-based aggregationSample-based range-partitioned sort