Database Query Performance: The Five Patterns That Hurt the Most
Database query performance problems usually come from a small set of recurring patterns. The N plus one query that issues many queries instead of one. The sequential scan that ignores indexes. The unbounded result set that grows with the database. The cross join that produces a cartesian product. The lock contention that serializes work that could have been concurrent. Fix these five and most database performance work is done.
Written by Yashveer Singh, founder of Yashveer Labs.
What you actually need to know
- N plus one queries, sequential scans, unbounded results, cross joins, and lock contention.
- These five patterns dominate database performance issues.
- EXPLAIN ANALYZE reveals which pattern is hurting any given query.
- Each pattern has a known fix.
- Most teams have one or two of these dominating their issues.
| Pattern | Symptom | Fix |
|---|---|---|
| N plus one | Burst of similar queries | Eager load or JOIN |
| Sequential scan | Slow query, EXPLAIN shows seq scan | Add the right index |
| Unbounded result | Memory blow up, slow response | LIMIT or paginate |
| Cross join | Query never finishes | Explicit join conditions |
| Lock contention | Intermittent slowness, deadlocks | Shorter transactions, ordered access |
The core argument
Database performance problems look diverse in symptoms but reduce to a small set of patterns in cause. The slow page that the team has been debugging for weeks is usually one of five things. The N plus one. The missing index. The unbounded result. The bad join. The lock contention. The fix is mechanical once the pattern is identified.
The discipline is to recognize the pattern from the symptom. Burst of similar queries in the log is N plus one. EXPLAIN showing sequential scan on a large table is a missing index. Memory spike on a specific endpoint is an unbounded result. Query that never returns is a cross join. Intermittent slowness with deadlock messages is lock contention.
The teams that learn these five patterns recognize most performance problems in minutes. The teams that do not spend weeks investigating each new symptom. The investment in learning the patterns is hours. The savings on debugging time compound across every performance problem the team ever faces.
The other discipline is to catch the patterns in code review. Each of the five has tells in the code. A query inside a loop that does not look batched. A WHERE clause without an indexed column. A query without LIMIT. A JOIN that is missing the ON clause. A transaction that holds the lock for too long. The reviewer who knows the patterns catches them before they reach production.
The five patterns in detail
The N plus one. A loop calls the ORM to fetch related data for each item. The total query count is one for the outer query plus N for the inner queries. The fix is to use the ORM's eager loading capability or to write a JOIN that fetches everything in one query.
The sequential scan. The query has a WHERE clause on a column without an index. The database reads every row. EXPLAIN shows the seq scan. The fix is to add the right index. The query usually drops from seconds to milliseconds.
The unbounded result. The query returns all matching rows without a LIMIT. At small data size the result is fine. At large data size the result is megabytes or gigabytes. The application slows. The memory grows. The fix is LIMIT plus pagination, or a tighter filter.
The cross join. A JOIN written without a proper ON clause, often as a typo or a misunderstanding of the data model. The result is the cartesian product of the two tables. The query never returns. The fix is to add the explicit join condition with the right columns.
The lock contention. Two transactions want the same row. One blocks the other. Under load the contention cascades. The fix is shorter transactions, accessing rows in a consistent order, and advisory locks for known hot paths.
How much does this cost
The cost of learning the patterns is hours. The cost of fixing them when found is minutes to hours per occurrence. The savings on customer facing performance is significant. The math is favorable.
Features the performance discipline must have
- Slow query log enabled with a reasonable threshold.
- pg_stat_statements or equivalent for query analysis.
- APM tool that captures query timing per endpoint.
- Code review that catches the patterns.
- A practice of running EXPLAIN ANALYZE on suspect queries.
- Performance regression tests for the critical paths.
- An owner for query performance.
Expert opinion
The teams that own database performance well learn the five patterns and recognize them quickly. The teams that do not own it spend weeks on each new performance investigation. The patterns are stable across databases and across years. The investment in learning them is hours. The return compounds across every performance investigation the team ever runs.
>
Yashveer Singh, founder of Yashveer Labs
How this played out on a real project
A client SaaS reported that their dashboard was slow. The team had spent two weeks investigating. We ran EXPLAIN ANALYZE on the dashboard's main query and the burst of follow up queries.
The main query was fine. The follow up queries were a classic N plus one. The dashboard fetched twenty items and then fetched related data for each item one at a time. Twenty one queries per dashboard load. We rewrote it with eager loading. The dashboard latency dropped from 1800 milliseconds to 140.
The same investigation found a missing index on a frequently used filter. Adding the index dropped another slow query from 400 milliseconds to 5. The two fixes took half a day. The dashboard felt fast for the first time in months.
For more on the related work, see the N+1 query problem detection prevention and refactoring and EXPLAIN ANALYZE a tour of PostgreSQLs best diagnostic tool.
Common mistakes teams make
- Ignoring the slow query log.
- Not running EXPLAIN ANALYZE on suspect queries.
- Pagination only on user facing lists, not on internal queries.
- JOIN syntax mistakes that produce cross joins.
- Long transactions that produce contention.
- No code review for the patterns.
- Treating performance as solved after the first fix.
- Treating database scaling as the answer when the patterns are the cause.
A 30 day query performance plan
- Week one. Enable the slow query log. Identify the top offenders.
- Week two. Run EXPLAIN ANALYZE on each. Categorize by pattern.
- Week three. Fix the top five. Measure.
- Week four. Establish the weekly review cadence.
For more on the related work, read the N+1 query problem detection prevention and refactoring and database indexes a practical primer for SaaS engineers. On the broader performance side, backend performance budgets how to set them is the natural next read.
Frequently asked
Why I am the right person for this kind of build
I do not have a degree yet. I do not need one. I have shipped Dwarka Bricks, Expert Tutorials, Prominence Football Academy, Velmora, and Nexli. The work is on real URLs, used by real people. Yashveer Singh, founder of Yashveer Labs. If the topic on this page is the one you are facing right now, I have done it for someone else and I can do it for you.
Posts that line up with this one.
- Performance Optimization
EXPLAIN ANALYZE: A Tour of PostgreSQL's Best Diagnostic Tool
EXPLAIN ANALYZE is the most useful Postgres tool most engineers never master. The output looks scary. The patterns are simple. Here is the tour that makes it useful in your daily work.
- Performance Optimization
The Caching Hierarchy: Browser, CDN, Edge, Application, Database
Every web application has five caching layers. Understanding which one to use for which data is how fast applications stay fast at scale.
- Performance Optimization
Connection Pooling: Why Defaults Are Wrong for Most Stacks
Every framework ships connection pool defaults. Almost none of them match your actual workload. The defaults are designed for the general case. Your workload is specific. Here is how to pick the right numbers.
- Performance Optimization
The Cost of Over-Caching: Stale Data Stories
Caching solves performance problems. Over-caching creates correctness problems. Here is the taxonomy of stale data bugs and how to prevent them.