Initial commit
This commit is contained in:
92
skills/smart-debugging/examples/performance-bug-debug.md
Normal file
92
skills/smart-debugging/examples/performance-bug-debug.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Performance Bug Debug Example
|
||||
|
||||
Debugging slow database queries and N+1 problems.
|
||||
|
||||
## Symptom
|
||||
|
||||
API endpoint taking 4.5 seconds to respond (target: < 200ms).
|
||||
|
||||
## Profiling
|
||||
|
||||
```python
|
||||
import cProfile
|
||||
import pstats
|
||||
|
||||
profiler = cProfile.Profile()
|
||||
profiler.enable()
|
||||
|
||||
response = await get_users_with_posts()
|
||||
|
||||
profiler.disable()
|
||||
stats = pstats.Stats(profiler)
|
||||
stats.sort_stats('cumulative')
|
||||
stats.print_stats(10)
|
||||
```
|
||||
|
||||
### Profile Output
|
||||
|
||||
```
|
||||
ncalls tottime percall cumtime percall filename:lineno(function)
|
||||
100 4.321 0.043 4.321 0.043 database.py:42(execute_query)
|
||||
1 0.089 0.089 4.410 4.410 users.py:15(get_users_with_posts)
|
||||
```
|
||||
|
||||
**Issue**: Database query called 100 times! (N+1 problem)
|
||||
|
||||
## Code Analysis
|
||||
|
||||
```python
|
||||
# BAD: N+1 Query Problem
|
||||
async def get_users_with_posts():
|
||||
users = await db.users.find_all() # 1 query
|
||||
|
||||
result = []
|
||||
for user in users: # 100 iterations
|
||||
posts = await db.posts.find({"user_id": user.id}) # N queries!
|
||||
result.append({"user": user, "posts": posts})
|
||||
|
||||
return result # Total: 101 queries (1 + 100)
|
||||
```
|
||||
|
||||
## Fix: Use Join/Eager Loading
|
||||
|
||||
```python
|
||||
# GOOD: Single Query with Join
|
||||
async def get_users_with_posts():
|
||||
query = """
|
||||
SELECT
|
||||
users.*,
|
||||
json_agg(posts.*) as posts
|
||||
FROM users
|
||||
LEFT JOIN posts ON posts.user_id = users.id
|
||||
GROUP BY users.id
|
||||
"""
|
||||
result = await db.execute(query) # 1 query total!
|
||||
return result
|
||||
```
|
||||
|
||||
## Performance Comparison
|
||||
|
||||
| Approach | Queries | Time |
|
||||
|----------|---------|------|
|
||||
| **Before (N+1)** | 101 | 4.5s ❌ |
|
||||
| **After (Join)** | 1 | 85ms ✅ |
|
||||
|
||||
**Improvement**: 53x faster!
|
||||
|
||||
## Prevention
|
||||
|
||||
1. **Query logging**: Log all database queries in development
|
||||
2. **Performance tests**: Assert query count < threshold
|
||||
3. **APM monitoring**: Track query patterns in production (Datadog, New Relic)
|
||||
|
||||
```python
|
||||
# Performance test
|
||||
def test_get_users_with_posts_query_count(query_counter):
|
||||
get_users_with_posts()
|
||||
assert query_counter.count <= 1, f"Expected 1 query, got {query_counter.count}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Result**: N+1 detected and fixed. Performance SLA met (< 200ms).
|
||||
Reference in New Issue
Block a user