The Shape of Waiting

A hard SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.

Domain
SQL
Difficulty
hard
Seniority
L4
Asked in
Vesta Innovations

Problem

We're running a latency review across the API and want to see how each endpoint's response times spread out rather than collapse into a single average. Split every endpoint's calls into four equal-sized tiers from fastest to slowest, and for each endpoint-tier report the fastest, slowest, and average latency, skipping any call that has no recorded latency. Lay the report out one endpoint at a time in alphabetical order, and within each endpoint walk its tiers from the fastest group down to the slowest.

Every request waits its turn, and some wait far longer than the rest. Map where the patience runs out.

Tables

api_calls

Columns: call_id INTEGER, endpoint TEXT, method TEXT, status INTEGER, latency REAL, user_id INTEGER, call_time TEXT, err_msg TEXT

api_calls: 10 of 670 rows
call_idendpointmethodstatuslatencyuser_idcall_timeerr_msg
8079/api/v1/ordersPOST2004.21002026-02-02 01:07:00NULL
8158/api/v2/productsPUT2007.91972026-03-03 02:14:00NULL
8237/api/v1/searchDELETE20111.62942026-04-04 03:21:00NULL
8316/api/v1/auth/loginPATCH20415.33912026-05-05 04:28:00NULL
8395/api/v1/auth/logoutget30119NULL2026-06-06 05:35:00NULL
8474/api/v2/analyticspost40022.75852026-07-07 06:42:00Not found
8553/api/v1/paymentsGET40126.46822026-08-08 07:49:00Unauthorized
8632/api/v1/users/POST40330.17792026-09-09 08:56:00Rate limit exceeded
8711/api/v2/products/PUT40433.88762026-01-10 09:03:00Internal server error
8790/api/v1/usersDELETE50037.5NULL2026-02-11 10:10:00Bad gateway

Expected output

First 5 of 42 rows
endpointbucketmin_latencymax_latencyavg_latency
/api/v2/products181.981.981.9
/api/v1/auth/login11095.256.1
/api/v1/auth/login2102.3194.6145.88947368421054
/api/v1/auth/login3200.3294247.7555555555556
/api/v1/auth/login4301.11627.2811.9722222222222

Worked solution and explanation

What this is really testing

This is per-endpoint equal-count bucketing wearing a performance-review costume. 'Four equal-sized tiers' means each tier holds a quarter of that endpoint's calls, not a quarter of its latency range. Latency is skewed, so slicing MAX(latency) - MIN(latency) into four equal widths dumps most calls into the fastest band and leaves the slow bands nearly empty. Anyone can reach for NTILE. The trap is where it goes: the tiering has to restart per endpoint, run over non-null latencies only, and finish before you aggregate. Bucket the whole table at once, or let NULL latencies into the sort, and every tier boundary shifts underneath you.


Building it

Step 1: Tier each endpoint's calls

In the tiered CTE, order each endpoint's calls by latency and label them with NTILE(4) OVER (PARTITION BY endpoint ORDER BY latency). The PARTITION BY endpoint is what makes tier 1 the fastest quarter of that endpoint, not of the whole API. Put WHERE latency IS NOT NULL here, so untimed calls never take a slot in the ordering.

Step 2: Summarize each tier

Outside the CTE, GROUP BY endpoint, bucket and compute MIN(latency), MAX(latency) and AVG(latency). You are now at the endpoint-tier grain, coarser than the per-row grain the window produced. MIN and MAX are the tier's edges; AVG is its center.

Step 3: Order the output

ORDER BY endpoint, bucket gives the sequence the preview shows: endpoints alphabetically, then tiers 1 through 4. That pair is unique per output row, so no further key is needed. The padded ' /api/v2/products' leads because of its leading space.


The solution

Per-endpoint latency tiers
WITH tiered AS (
    SELECT endpoint,
           latency,
           NTILE(4) OVER (PARTITION BY endpoint ORDER BY latency) AS bucket
    FROM api_calls
    WHERE latency IS NOT NULL
)
SELECT endpoint,
       bucket,
       MIN(latency) AS min_latency,
       MAX(latency) AS max_latency,
       AVG(latency) AS avg_latency
FROM tiered
GROUP BY endpoint, bucket
ORDER BY endpoint, bucket
Global tiers (wrong grain)
NTILE(4) OVER (ORDER BY latency) with no partition tiers the entire table at once. A slow endpoint's fastest calls can land in tier 3 or 4 because they are slow relative to the whole API. The tiers no longer describe any single endpoint.
Per-endpoint tiers (correct)
NTILE(4) OVER (PARTITION BY endpoint ORDER BY latency) restarts at every endpoint, so tier 1 is always that endpoint's own fastest quarter. That reset is what makes the endpoints comparable.

Common follow-up questions