The Pattern
You fetch a list of N parent rows with one query, then for each parent you run another query to load a related child. That is one query for the list plus N for the children, an n plus one. Each query may be fast, but the count explodes and the round trips dominate latency.
Why It Hides
ORMs make related data look like plain object access. Reading a field on each item silently fires a query. The code reads cleanly while the database sees a storm of nearly identical lookups that only appear under real data volume.
How to Detect It
- Count queries per request in logs or traces; a request firing dozens of similar statements is a strong signal.
- Look in query stats for a statement with a very high call count and a parameter that varies by id.
- Watch for latency that grows with the size of a list.
Fixing It
- Eager load the related rows in one query with a join or a single batched fetch by ids.
- Use a data loader that collects ids during a tick and resolves them in one round trip.
Key idea
An n plus one runs one query per item in a list, so detect it by counting queries per request and fix it by eager loading or batching the children.