An N+1 query problem is a loop that runs one separate database query per item instead of batching them into a single query — the classic pattern behind a huge share of WordPress performance problems. A normal WordPress page load already runs 20-100 queries; a standard WooCommerce product page can run over 200. Query Monitor is the free plugin that makes these visible, and fixing what it finds is usually the single biggest performance win available before you touch caching or hosting at all.
What an N+1 Query Actually Looks Like
You can spot the pattern by looking for repeated queries with different IDs — the same query template run 20 times for 20 different post IDs, instead of one query fetching all 20 at once with a single WHERE id IN (...). This typically comes from a loop like: fetch a list of posts, then inside the loop, fetch each post’s meta, author, or related data one at a time. Multiply that by the number of items on the page and you get a query count that scales with content instead of staying flat.
Finding Them with Query Monitor
- Install Query Monitor on a staging copy (or carefully, with output visible only to admins, on production).
- Load the slow page and open the Query Monitor panel in the admin bar.
- Look at the Queries panel, grouped by caller — a single function or hook responsible for dozens of near-identical queries is your N+1 candidate.
- Check the query count against page complexity. A product listing page running 300+ queries for 20 products is a strong signal something isn’t batching.
- Identify which plugin or theme code owns that caller — Query Monitor shows the file and line, so you’re not guessing.
Fixing What You Find
| Pattern | Fix |
|---|---|
| Meta fetched per-post in a loop | Use update_meta_cache() or a single query with the post IDs up front |
| Related posts/products fetched one at a time | Batch with WP_Query‘s post__in instead of a query per item |
| Repeated identical queries across a page | Cache the result in a variable or transient instead of re-querying |
Custom plugin code with a query inside a foreach |
Move the query outside the loop, fetch once, then loop over the results |
Why This Beats Tuning MySQL First
The single biggest database performance improvement usually comes from fixing bad queries, not tuning MySQL configuration — a query doing a full table scan or running 200 times instead of once will be slow regardless of server tuning. Object caching (Redis or Memcached) can eliminate 80-90% of database queries on a fully loaded page, but it’s most effective once the underlying query pattern is actually efficient; caching a bad N+1 pattern just makes it slightly-less-bad instead of fixing it. We cover broader database housekeeping in WordPress Database Optimization: A 2026 Cleanup Guide.
If you want a page’s query pattern audited, get in touch.
Frequently Asked Questions
Is Query Monitor safe to run on a live production site?
It’s generally safe since output is only visible to logged-in users with the right capability by default, but it does add a small overhead while active — best practice is to diagnose on staging, or enable it briefly on production and disable it once you’ve captured what you need.
How many database queries is too many for one page?
There’s no universal number, but if a page’s query count scales up noticeably as content grows (more products, more posts), that’s the signal of an N+1 pattern rather than a fixed, reasonable query budget.
Will object caching fix N+1 queries without changing code?
It reduces the cost of repeated identical queries, but it doesn’t fix the underlying pattern. A genuinely broken N+1 loop still needs a code fix to batch the queries properly — caching just masks part of the symptom.
Featured image: original illustration.
