Server

N+1 query

Also called N+1.

N+1 query is a pattern where code runs one query to fetch a list of N rows and then one more query per row to fetch related data. The page makes N+1 round trips where two would do.

How it is measured

Count queries per request. Enable the query log, an APM trace or a tool like Query Monitor for WordPress, and look for the same statement repeated with different ids. Anything above a few dozen identical statements in one request is the signature.

The cost is queries multiplied by round-trip time. 120 queries at 1.5 ms each add 180 ms before any slow statement is involved, and it grows with the list length.

Worked example

A WordPress archive template loops through 50 posts and calls `get_post_meta` and `get_the_author` inside the loop with caching off. The page runs 214 queries and takes 760 ms. Each query is fast, 1 to 2 ms.

Priming the meta cache with one query and fetching authors in a single `IN` lookup brings it down to 9 queries and 140 ms. A list of 200 posts would have taken 3 seconds before the fix.

How it differs

An N+1 query is many small queries where one join or batch would do. A slow query is one statement that takes too long on its own. N+1 excludes any single expensive statement, each query can be fast. A slow query excludes the repetition, and one index may be the whole fix.

Common errors

Looking only at the slow query log, which will not list a hundred 2 ms queries. Fixing it with a bigger server. Loading relations lazily inside templates. Adding an index and expecting the count to fall. Testing with 5 rows in development and 5,000 in production.

In practice

Install a query counter on your staging site and load your busiest list page. If the count scales with the number of rows, batch the lookup with eager loading, a join or a prefetch.

See also

Slow query, Query plan

Sources

Count this on a real site.

Watch my website