Skip to main content
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.