## TL;DR
Scope the N+1 measurement to a single request. On a paginated list, the per-row queries run once per row on the current page: 20 rows means at most 20 queries, bounded by the page size, not the table size. That is not an N+1 worth flagging. Flag it only when the query count scales with total rows rather than page size.

## The query

```text
agent reported an N+1 on a paginated list but the per-row queries only ran on the current page -- 20 rows, not 2000
```

## Use this when

- An N+1 alert fires on a paginated endpoint
- The per-row queries are bounded by the page size (20, 50, 100)
- The "2000 queries" number came from multiplying by total rows, not measuring a request
- The endpoint response time is fine and nobody complained

## Not for

- A genuine N+1 with no pagination bound (all rows loaded, then per-row queries)
- Dataloader or batching misconfiguration on a hot endpoint
- Retry storms counted as duplicates
- N+1s on non-paginated endpoints

## Steps

### 1. Measure one request, not the table

Pick a single page request and count the queries it actually issues: 1 query for the page + up to `page_size` per-row queries. Write down the real number.

Expected output: a concrete count like "21 queries for page 1 (1 + 20 rows)."

### 2. Check the bound

Confirm the count is bounded by the page size: page 2 also issues ~21, page 50 also ~21. If the count never exceeds `1 + page_size` regardless of which page you fetch, the "N" in N+1 is the page size, and it is constant.

Expected output: the same query count across different pages.

### 3. Compare against the alternative honestly

Batching the per-row queries into one IN query would save ~19 round trips per request. On a page that renders in 80ms, that saves single-digit milliseconds. Write down the actual saving before optimizing.

Expected output: a measured or estimated saving, usually tiny.

### 4. Only flag the unbounded case

Flag it as an N+1 only if the per-row queries scale with total rows: no pagination, page size set to "all," or the client paginates through every page in a loop. Bounded-per-page is a code-smell note at most, not an alert.

Expected output: the alert fires only for genuinely unbounded patterns.

### 5. Fix the detector's scope

Change the N+1 detector to group queries by request (trace ID), not by endpoint or table. The alert threshold should be "queries per request exceeds 1 + page_size by a wide margin," not a raw count.

Expected output: paginated endpoints stop generating false alerts.

## Variant phrasings

### agent flagged 300 duplicate queries on a background job

Same scoping error in a different costume. A nightly bulk import is not a hot endpoint; the per-row cost that matters is per-run, and batching a background job is a different tradeoff than batching a request.

### agent said 1200 queries per request

Check whether the trace includes the agent's own instrumentation queries (step 1). Then check pagination (step 2). Either one collapses the number.

### N+1 alert on an endpoint nobody complained about

Trust the complaint data. If p99 is fine and the count is bounded, the detector is noisier than the problem. Tune it (step 5) instead of "fixing" the code.

## Why it happens

The detector counts query executions per endpoint and compares against a threshold, with no notion of request scope. A paginated list serving 100 pages a day issues 2,000 per-row queries a day, which looks enormous in aggregate and trivial per request. The agent multiplied where it should have divided: the cost that matters is per request, and per request it is bounded.

## Edge cases

- Page size configurable by the client: if callers can pass `page_size=10000`, the bound is whatever the max page size is. Cap the max page size server-side; then the analysis holds.
- "Load more" infinite scroll: each page fetch is still one bounded request. The detector must not sum across the scroll session.
- Export endpoints that paginate internally: an export that loops all pages server-side IS unbounded from the request's perspective. That one deserves the flag.
- The per-row query is itself slow: 20 slow queries per page is a real problem even though it is bounded. That is a slow-query problem, not an N+1 problem; fix the query, not the pattern.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_IBYZmISDKkzo6nvs1IP8Ow
