| name | performance-patterns |
| description | Use when user asks about N+1 queries, performance optimization, query optimization, reduce API calls, improve render performance, fix slow code, optimize database, or reduce bundle size. Provides guidance on identifying and fixing performance anti-patterns across database, backend, frontend, and API layers. |
| allowed-tools | Read, Grep, Glob |
Performance Anti-Patterns Reference
N+1 Query Problem
The N+1 problem occurs when code executes N additional queries to fetch related data for N items from an initial query.
Identification:
- Queries inside loops
- Lazy loading of associations during iteration
- GraphQL resolvers fetching per-item
Fix Strategies:
- Eager Loading: Load related data in initial query
- Batching: Collect IDs, fetch all at once
- DataLoader: For GraphQL, batch and cache per-request
- Denormalization: Store computed/related data together
Severity: HIGH - Scales linearly with data size, causes exponential slowdown
Over-Fetching
Retrieving more data than needed from API or database.
Identification:
- SELECT * queries
- API endpoints returning full objects
- No field selection support
- Loading nested relations by default
Fix Strategies:
- Field Selection: Only query needed columns
- Sparse Fieldsets: Support
?fields=id,nameparameter - GraphQL: Let clients specify exact fields
- DTOs: Map to response-specific objects
Severity: MEDIUM - Increases bandwidth, memory, serialization time
Under-Fetching
Requiring multiple requests to get needed data.
Identification:
- Waterfall requests (request depends on previous)
- Multiple endpoints for related data
- No include/expand support
Fix Strategies:
- Compound Endpoints:
/users?include=orders - GraphQL: Single query for nested data
- BFF Pattern: Backend aggregates for frontend
- Parallel Requests: When dependencies allow
Severity: MEDIUM - Increases latency, connection overhead
Missing Pagination
Returning unbounded result sets.
Identification:
- List endpoints without limit
findAll()without pagination- No cursor for large datasets
Fix Strategies:
- Offset Pagination:
?page=1&limit=20 - Cursor Pagination:
?cursor=abc&limit=20(better for large sets) - Default Limits: Always apply max limit server-side
- Streaming: For very large exports
Severity: HIGH - Can crash server/client with large data
Inefficient Algorithms
O(n²) or worse complexity where better solutions exist.
Identification:
- Nested loops on collections
- Repeated array.find/includes in loops
- String concatenation in loops
- Sort inside loops
Fix Strategies:
- Use Maps/Sets: O(1) lookup instead of O(n)
- Single Pass: Combine operations
- Pre-compute: Calculate once, reuse
- Better Algorithms: Binary search for sorted data
Severity: HIGH - Becomes unusable with large data
Unnecessary Re-renders (Frontend)
Components re-rendering when their output hasn't changed.
Identification:
- Inline objects/arrays in JSX
- Inline function handlers
- Missing React.memo/useMemo/useCallback
- Context changes affecting all consumers
Fix Strategies:
- Memoization: React.memo for components
- Stable References: useMemo for objects, useCallback for functions
- Context Splitting: Separate frequently-changing state
- Selectors: Only subscribe to needed state slices
Severity: MEDIUM-HIGH - Causes janky UI, especially on lists
Sequential Async Operations
Running async operations one-by-one when parallel is possible.
Identification:
- Sequential await statements
- Waterfall promises
- Loop with await inside
Fix Strategies:
- Promise.all: Run independent operations in parallel
- Promise.allSettled: When some can fail
- Batching: Group operations efficiently
- Pipelining: Stream processing
Severity: MEDIUM - Multiplies latency
Quick Reference by Layer
Database
| Issue | Detect | Fix |
|---|---|---|
| N+1 queries | Query in loop | Eager load / batch |
| Missing index | Slow WHERE/JOIN | Add index |
| SELECT * | No column list | Specify columns |
| No LIMIT | Unbounded query | Add pagination |
Backend
| Issue | Detect | Fix |
|---|---|---|
| O(n²) loop | Nested iteration | Use Set/Map |
| Sequential await | await in sequence | Promise.all |
| Sync I/O | fs.readFileSync | Use async version |
| No caching | Repeated computation | Memoize |
Frontend
| Issue | Detect | Fix |
|---|---|---|
| Re-renders | Inline objects/functions | Memoize |
| Bundle size | Large imports | Tree-shake/split |
| Memory leak | No cleanup | useEffect cleanup |
| Layout thrash | Read+write DOM | Batch DOM ops |
API
| Issue | Detect | Fix |
|---|---|---|
| Over-fetching | All fields returned | Field selection |
| Under-fetching | Multiple requests | Include/expand |
| No pagination | Unbounded lists | Add limit/cursor |
| N+1 calls | Fetch in loop | Batch endpoint |