Performance Review
Identify bottlenecks, inefficiencies, and scalability risks in code changes.
Analysis Process
- Read affected files -- understand data access patterns, algorithmic complexity, and resource usage
- Identify N+1 queries -- look for ORM calls inside loops, missing eager loading, unbatched database access
- Check algorithmic complexity -- nested loops over collections, repeated linear scans, unnecessary sorting
- Evaluate memory usage -- large object allocations, unbounded caches, retained references, memory leaks
- Review database patterns -- missing indexes, full table scans, unoptimized joins, excessive round trips
- Check caching -- missing cache layers, cache invalidation issues, redundant computations
- Assess bundle/payload size -- unnecessary imports, large dependencies, uncompressed responses
- Review rendering performance -- unnecessary re-renders, missing memoization, layout thrashing (frontend)
Output Format
Structure findings as:
## Performance Analysis
### Critical Issues
Issues that will cause noticeable degradation at scale.
- [issue] -- where in the code, why it matters, estimated impact
### N+1 Query Detection
| Location | Pattern | Fix |
|----------|---------|-----|
| file:line | Description of the N+1 | Eager load / batch / join |
### Algorithmic Complexity
| Location | Current | Suggested | Why |
|----------|---------|-----------|-----|
| file:line | O(n^2) | O(n) | Description |
### Database Concerns
- Missing indexes, unoptimized queries, excessive round trips
### Memory Concerns
- Unbounded growth, large allocations, retained references
### Caching Opportunities
- Computations or queries that could benefit from caching
### Recommendations
- [recommendation] -- priority (critical/warning/suggestion), estimated impact
Common Patterns to Flag
N+1 Queries
// Bad: N+1 -- one query per user inside loop
const users = await userRepo.find();
const profiles = await Promise.all(users.map(u => profileRepo.findOne({ userId: u.id })));
// Good: Single query with join or batch
const users = await userRepo.find({ relations: ["profile"] });
Unnecessary Re-computation
// Bad: Recomputes on every call
const getExpensiveResult = () => heavyComputation(data);
// Good: Compute once, reuse
const expensiveResult = heavyComputation(data);
Unbounded Collection Growth
// Bad: Cache grows without limit
const cache = new Map();
const get = (key) => { if (!cache.has(key)) cache.set(key, compute(key)); return cache.get(key); };
// Good: LRU or bounded cache
const cache = new LRUCache({ max: 1000 });
Rules
- Focus on the specific changes proposed, not a full performance audit of the entire codebase
- Flag only real performance risks -- do not micro-optimize code that runs once at startup
- Quantify impact where possible (O(n) vs O(n^2), number of database round trips, estimated payload size)
- Distinguish between critical issues (will degrade at scale) and suggestions (marginal improvement)
- If the changes have no performance implications, report "No performance concerns" and explain why
- Always consider the data scale -- an O(n^2) over 5 items is fine, over 10,000 is not
1---2name: lisa-performance-review3description: Performance review methodology4---56# Performance Review78Identify bottlenecks, inefficiencies, and scalability risks in code changes.910## Analysis Process11121. **Read affected files** -- understand data access patterns, algorithmic complexity, and resource usage132. **Identify N+1 queries** -- look for ORM calls inside loops, missing eager loading, unbatched database access143. **Check algorithmic complexity** -- nested loops over collections, repeated linear scans, unnecessary sorting154. **Evaluate memory usage** -- large object allocations, unbounded caches, retained references, memory leaks165. **Review database patterns** -- missing indexes, full table scans, unoptimized joins, excessive round trips176. **Check caching** -- missing cache layers, cache invalidation issues, redundant computations187. **Assess bundle/payload size** -- unnecessary imports, large dependencies, uncompressed responses198. **Review rendering performance** -- unnecessary re-renders, missing memoization, layout thrashing (frontend)2021## Output Format2223Structure findings as:2425```26## Performance Analysis2728### Critical Issues29Issues that will cause noticeable degradation at scale.3031- [issue] -- where in the code, why it matters, estimated impact3233### N+1 Query Detection34| Location | Pattern | Fix |35|----------|---------|-----|36| file:line | Description of the N+1 | Eager load / batch / join |3738### Algorithmic Complexity39| Location | Current | Suggested | Why |40|----------|---------|-----------|-----|41| file:line | O(n^2) | O(n) | Description |4243### Database Concerns44- Missing indexes, unoptimized queries, excessive round trips4546### Memory Concerns47- Unbounded growth, large allocations, retained references4849### Caching Opportunities50- Computations or queries that could benefit from caching5152### Recommendations53- [recommendation] -- priority (critical/warning/suggestion), estimated impact54```5556## Common Patterns to Flag5758### N+1 Queries59```typescript60// Bad: N+1 -- one query per user inside loop61const users = await userRepo.find();62const profiles = await Promise.all(users.map(u => profileRepo.findOne({ userId: u.id })));6364// Good: Single query with join or batch65const users = await userRepo.find({ relations: ["profile"] });66```6768### Unnecessary Re-computation69```typescript70// Bad: Recomputes on every call71const getExpensiveResult = () => heavyComputation(data);7273// Good: Compute once, reuse74const expensiveResult = heavyComputation(data);75```7677### Unbounded Collection Growth78```typescript79// Bad: Cache grows without limit80const cache = new Map();81const get = (key) => { if (!cache.has(key)) cache.set(key, compute(key)); return cache.get(key); };8283// Good: LRU or bounded cache84const cache = new LRUCache({ max: 1000 });85```8687## Rules8889- Focus on the specific changes proposed, not a full performance audit of the entire codebase90- Flag only real performance risks -- do not micro-optimize code that runs once at startup91- Quantify impact where possible (O(n) vs O(n^2), number of database round trips, estimated payload size)92- Distinguish between critical issues (will degrade at scale) and suggestions (marginal improvement)93- If the changes have no performance implications, report "No performance concerns" and explain why94- Always consider the data scale -- an O(n^2) over 5 items is fine, over 10,000 is not