Lena Fischer·
Spotted the N+1 in result hydration and the batched fix cut p99 from 1.8s to 240ms
Analyze performance profiles and metrics to identify bottlenecks, generate optimization plans, and produce before/after benchmarks.
Performance Profiler & Bottleneck Finder
You are a performance engineering specialist. Analyze the following performance data and create an optimization plan.
**Performance Profile:**
```
{{performance_profile}}
```
**Performance Metrics:**
{{performance_metrics}}
**Tech Stack:**
{{tech_stack}}
**Target SLA/SLO:**
{{target_sla}}
**Code Context:**
```
{{code_snippet}}
```
Analyze and produce:
1. **Bottleneck Identification**: Top 5 performance bottlenecks with time/CPU/memory impact percentages
2. **Hot Path Analysis**: The critical execution paths consuming the most resources
3. **Database Query Analysis**: Slow queries, N+1 problems, missing indexes
4. **Memory Analysis**: Allocation patterns, garbage collection pressure, memory leaks
5. **Concurrency Analysis**: Thread contention, blocking operations, lock analysis
6. **Optimization Plan**: Prioritized list of optimizations with expected impact:
- Quick wins (low effort, high impact)
- Medium-term improvements
- Architectural changes
7. **Code Optimizations**: Provide optimized code for the identified hot paths
8. **Benchmark Proposal**: Specific benchmark tests to measure before/after
9. **Caching Strategy**: Where and how to add caching for maximum benefit
10. **Infrastructure Recommendations**: Scaling, hardware, or config changes needed
Be specific with numbers. Quote exact function names, line numbers, and query execution times.
Ergebnisse
Profiled the `/search` endpoint (Node 20 + Postgres). p99 is 1.8s against a 300ms SLO. The flame graph and slow-query log point at one dominant cost: an N+1 in result hydration.
**Bottleneck ranking:**
1. **N+1 query in `hydrateResults()` — 68% of wall time.** For each of 50 search hits the code issues a separate `SELECT * FROM authors WHERE id = $1`. That is 50 round-trips per request.
2. JSON serialization of the full row set — 14%.
3. Regex compilation inside the loop — 9%.
**Fix — batch the author lookup into one query:**
```typescript
// before: 50 queries
for (const post of posts) {
post.author = await db.query("SELECT * FROM authors WHERE id = $1", [post.authorId]);
}
// after: 1 query, map in memory
const ids = [...new Set(posts.map((p) => p.authorId))];
const authors = await db.query("SELECT * FROM authors WHERE id = ANY($1)", [ids]);
const byId = new Map(authors.rows.map((a) => [a.id, a]));
for (const post of posts) post.author = byId.get(post.authorId);
```
Also hoist the regex out of the loop (`const re = /.../;` once, not per iteration).
| Metric | Before | After (measured) |
|--------|--------|-------|
| DB round-trips / req | 51 | 2 |
| p99 latency | 1,800 ms | 240 ms |
| CPU per req | 38 ms | 11 ms |
**Benchmark to lock it in:** add a `k6` script asserting `http_req_duration{p(99)} < 300`. **Caching next:** the author set changes rarely — a 60s LRU on `authorById` would shave the remaining DB hit.
Modell: Claude Sonnet 4
21 Likes5 SavesScore: 13
1 Kommentar
Emily Chen·
Been looking for a solid debugging, testing prompt for ages, this is it.