Finding where time goes

Performance and scaling Mid-level Python 3.13+ PostgreSQL 17+ Reviewed By Best Latest Apps

Order the steps

Order a slow-endpoint investigation.

  • Profile or EXPLAIN that part
  • Confirm the regression with metrics and pick a slow trace
  • Read the trace to see which span dominates
  • Make one change and measure again

Choose an answer, then open Show answer below to check it.

Show answer

Answer: B C A D

  1. Confirm the regression with metrics and pick a slow trace Know what changed and when.
  2. Read the trace to see which span dominates Database, code or a downstream call.
  3. Profile or EXPLAIN that part Find the specific function or query.
  4. Make one change and measure again Keep it only if the numbers improve.

30-second answer

Measure before guessing. Start from traces: they show whether time is in your code, the database, or another service. If it's the database, look at the slow query log and EXPLAIN ANALYZE. If it's your code, profile: cProfile or a sampling profiler like py-spy on the live process shows which functions burn CPU, and a flame graph makes the hot path obvious. Fix the biggest cost, then measure again.

Practise saying it · 30 s. No recording, just a timer

Debug a slow endpoint.

Say your answer out loud, then check which of these points you covered:

  • Metrics and traces first
  • Query log, EXPLAIN
  • py-spy / cProfile
  • One change, re-measure

Deep dive

Sampling profilers (py-spy) add little overhead and can attach to production.

Wall time vs CPU time: a function waiting on I/O shows wall time but little CPU.

Compare against a baseline from before the regression.

Microbenchmarks with timeit help only once you know the hot spot.

Profile a function with cProfile Ran on Python 3.13.5 · mypy --strict
Python 3.13
import cProfile
import pstats


def slow_sum(n: int) -> int:
    return sum(i * i for i in range(n))


prof = cProfile.Profile()
prof.enable()
slow_sum(200_000)
prof.disable()
stats = pstats.Stats(prof)
print(stats.total_calls > 0)  # type: ignore[attr-defined]

Common mistakes

  • Optimising code that isn't on the hot path.
  • Profiling only on a laptop with toy data.
  • Changing several things at once.

Senior take & follow-ups

Traces first, then the right profiler, then one change at a time with measurements.

Follow-up questions

Think of your answer first, then open the hint.

  1. CPU-bound or I/O-bound: how do you tell?

    Show hint

    Compare CPU time with wall time, or look at the trace spans.

  2. What's a flame graph?

    Show hint

    Stacked call stacks where width is time spent.

Suggest a fix if something here is wrong or out of date.