Smooth Latency

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

Domain
SQL
Difficulty
medium
Seniority
L5

Problem

Some of our API endpoints look like they are drifting slower as traffic grows, and we want the underlying trend rather than the per-call noise. For each endpoint, report at every call the average latency across that call and every earlier one on the same endpoint (a call made at the same moment counts as earlier when its call_id is lower), skipping any call with no recorded latency.

Noisy latency readings, smoothed into a trend you can trust.

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 664 rows
endpointlatencyrunning_avg
/api/v2/products81.981.9
/api/v1/auth/login381.6381.6
/api/v1/auth/login70.2225.9
/api/v1/auth/logout191.3191.3
/api/v1/auth/logout398.9295.1

Worked solution and explanation

What this really is

Strip the SRE costume off and this is a per-endpoint cumulative average: at each call, the mean of that call and every earlier one for the same endpoint, in a single ordered pass. Anyone can reach for AVG. Two things separate the seniors. First, do you get there without a correlated subquery that re-averages every prior call per row (O(n^2), dead at two billion rows)? Second, do you nail the ordering? Order by call_time alone and tied timestamps advance in an arbitrary order, so your numbers are non-deterministic; lean on the ORDER BY default and you get RANGE, which lumps every call sharing a call_time into one step and makes the average jump in plateaus exactly where traffic bursts. The fix is a ROWS frame ordered by call_time then call_id, which also makes the naive correlated subquery (scoped with call_time <=) not just slow but wrong on ties.


Break down the requirements

Step 1: Filter nulls before windowing

The WHERE latency IS NOT NULL filter removes the ~0.1% of rows with missing latency before the window function runs. Filtering first is cheaper than letting the window absorb nulls.

Step 2: Partition by endpoint

PARTITION BY endpoint resets the running average for each endpoint independently. Without this, AVG accumulates across all endpoints and produces a meaningless global trend.

Step 3: Order, tiebreak, and frame

ORDER BY call_time, call_id fixes the sequence of calls: call_time gives chronological order, and call_id is the deterministic tiebreak so calls sharing a timestamp still advance one at a time. The frame ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW covers every call up to the current one, which is exactly the cumulative average definition.


The solution

Running average per endpoint
SELECT
    endpoint,
    latency,
    AVG(latency) OVER (
        PARTITION BY endpoint
        ORDER BY call_time, call_id
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS running_avg
FROM api_calls
WHERE latency IS NOT NULL

Common follow-up questions