N+1 queries
0-day streakReview

Your progress

Level 1

0 XP100 XP to level 2
0day streak
0best streak
0topics started
0cards reviewed
    Review cards

    Progress is stored only in this browser. No account is required.

    The N+1 query problem: the 60-second story

    The N+1 query problem

    101 queries to show 50 restaurant cards.

    Assume each takes half a millisecond: nothing looks slow. Together they’re a staircase of round trips your code never mentions.

    r.dishes looks like a field. It’s a database round trip.

    ORMs lazy-load an association on first touch. Right for one object, wrong inside a loop over fifty.

    Fix it with EAGER?

    Bad: Mark the relation EAGER

    It loads everywhere, and JPA still runs one select per row without JOIN FETCH.

    Good: Fetch per use case

    Each page loads what it needs, in bulk.

    ≈ 2 s

    for 51 lazy queries across regions

    Assume 40 ms per round trip from Singapore to Mumbai. The same page is 25.5 ms in one zone; batching makes it ≈ 80 ms.

    JOIN two collections and 50 cards become 60,000 rows

    30 dishes × 40 reviews per restaurant. JOIN to-one relations and at most one collection; load the rest with a second query.

    The fix: one trip with a basket

    1. Load the 50 restaurants
    2. Collect their ids
    3. Fetch every dish WHERE restaurant_id = ANY($1)
    4. Group the dishes by restaurant in memory

    1,000 page views a second, and a pool of 20 connections that looked generous.

    The catch

    By Little’s law, 25.5 ms per request holds ≈ 26 connections. Requests queue for the pool; batched, they hold ≈ 2.

    Parallel calls hide N+1 between services. They don’t fix it.

    Assume 3 ms a call. Ten at a time cuts 150 ms to 15, but the user service still gets 50 requests. Batch them.

    Remember

    Count queries per request, then load in bulk. JOIN to-ones, one ANY query per collection, a batch endpoint between services.