-
-
Notifications
You must be signed in to change notification settings - Fork 1
Example Database Debugging
A real-world scenario showing how to use ChronoTrace to debug database performance issues and query problems in a Laravel application.
Your users are complaining that the dashboard loads slowly. Let's use ChronoTrace to identify and fix the database performance issues.
- Dashboard taking 3-5 seconds to load
- Users experiencing timeouts
- Increased server load during peak hours
- No clear indication of what's causing the slowdown
Since this is a specific performance issue, let's use targeted recording to focus on the dashboard:
# Target the dashboard route
CHRONOTRACE_MODE=targeted
# In config/chronotrace.php
'targeted_routes' => [
'dashboard',
'dashboard/*',
'api/dashboard/*',
],Or start manual recording:
# Record dashboard requests for 10 minutes
php artisan chronotrace:record --routes="dashboard*" --duration=10mLet's create some dashboard requests to capture traces:
# Simulate dashboard access
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:8000/dashboard
# Or visit in browser while logged in
# Navigate to: http://localhost:8000/dashboardList traces to find slow dashboard requests:
# Find slow dashboard requests (>1 second)
php artisan chronotrace:list --route="dashboard*" --min-duration=1000
# Example output:
ββββββββββββββ¬ββββββββββββββββββββββ¬βββββββββ¬βββββββββββ¬ββββββββββββββββββ¬βββββββββββ
β Trace ID β Timestamp β Method β Status β Route β Duration β
ββββββββββββββΌββββββββββββββββββββββΌβββββββββΌβββββββββββΌββββββββββββββββββΌβββββββββββ€
β slow_001 β 2024-08-06 14:30:15 β GET β 200 β dashboard β 3,245ms β
β slow_002 β 2024-08-06 14:32:42 β GET β 200 β dashboard β 2,891ms β
β slow_003 β 2024-08-06 14:35:18 β GET β 200 β dashboard β 4,156ms β
ββββββββββββββ΄ββββββββββββββββββββββ΄βββββββββ΄βββββββββββ΄ββββββββββββββββββ΄βββββββββββLet's examine the database queries in a slow trace:
# Replay focusing on database events
php artisan chronotrace:replay slow_001 --filter=databaseββ DATABASE EVENTS (15 queries, 2,890ms total) ββββββββββββββββ
β [+0ms] SELECT * FROM users WHERE id = ? [123] (5ms)
β Connection: mysql, Rows: 1
β
β [+12ms] SELECT * FROM user_settings WHERE user_id = ? [123] (3ms)
β Connection: mysql, Rows: 1
β
β [+25ms] SELECT * FROM posts WHERE user_id = ? ORDER BY created_at DESC [123] (1,245ms) β οΈ
β Connection: mysql, Rows: 10,000
β
β [+1,280ms] SELECT * FROM comments WHERE post_id IN (?, ?, ?, ...) [1,2,3...] (892ms) β οΈ
β Connection: mysql, Rows: 50,000
β
β [+2,185ms] SELECT * FROM likes WHERE post_id IN (?, ?, ?, ...) [1,2,3...] (634ms) β οΈ
β Connection: mysql, Rows: 25,000
β
β [+2,845ms] SELECT * FROM users WHERE id IN (?, ?, ?, ...) [456,789...] (45ms)
β Connection: mysql, Rows: 500
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- N+1 Query Problem: Loading posts individually instead of eagerly loading
-
Missing Indexes: Slow queries on
posts.user_idandcomments.post_id - Over-fetching: Loading all posts instead of paginating
- Inefficient IN clauses: Large IN queries for comments and likes
Before (problematic code):
// In DashboardController.php
public function index()
{
$user = auth()->user();
// This will cause N+1 queries
$posts = $user->posts()->latest()->get();
foreach ($posts as $post) {
$post->comments; // N+1 query
$post->likes; // Another N+1 query
}
return view('dashboard', compact('posts'));
}After (optimized code):
// In DashboardController.php
public function index()
{
$user = auth()->user();
// Eager load relationships to prevent N+1
$posts = $user->posts()
->with(['comments' => function($query) {
$query->latest()->limit(5); // Only recent comments
}, 'likes', 'author'])
->latest()
->paginate(10); // Add pagination
return view('dashboard', compact('posts'));
}// Create migration: php artisan make:migration add_dashboard_indexes
public function up()
{
Schema::table('posts', function (Blueprint $table) {
$table->index(['user_id', 'created_at']); // Composite index
});
Schema::table('comments', function (Blueprint $table) {
$table->index(['post_id', 'created_at']);
});
Schema::table('likes', function (Blueprint $table) {
$table->index(['post_id', 'user_id']);
});
}// In DashboardController.php
public function index()
{
$user = auth()->user();
$cacheKey = "dashboard_posts_{$user->id}";
$posts = Cache::remember($cacheKey, 300, function() use ($user) {
return $user->posts()
->with(['comments' => function($query) {
$query->latest()->limit(5);
}, 'likes', 'author'])
->latest()
->paginate(10);
});
return view('dashboard', compact('posts'));
}After implementing the changes, let's test again:
# Run migrations
php artisan migrate
# Clear caches
php artisan cache:clear
php artisan config:clear
# Record new traces
php artisan chronotrace:record --routes="dashboard*" --duration=5mVisit the dashboard again and check the new traces:
# Check new performance
php artisan chronotrace:list --route="dashboard*" --since="5 minutes ago"
# Example improved output:
ββββββββββββββ¬ββββββββββββββββββββββ¬βββββββββ¬βββββββββββ¬ββββββββββββββββββ¬βββββββββββ
β Trace ID β Timestamp β Method β Status β Route β Duration β
ββββββββββββββΌββββββββββββββββββββββΌβββββββββΌβββββββββββΌββββββββββββββββββΌβββββββββββ€
β fast_001 β 2024-08-06 15:30:15 β GET β 200 β dashboard β 156ms β
β fast_002 β 2024-08-06 15:32:42 β GET β 200 β dashboard β 89ms β
β fast_003 β 2024-08-06 15:35:18 β GET β 200 β dashboard β 134ms β
ββββββββββββββ΄ββββββββββββββββββββββ΄βββββββββ΄βββββββββββ΄ββββββββββββββββββ΄βββββββββββphp artisan chronotrace:replay fast_001 --filter=databaseββ DATABASE EVENTS (3 queries, 89ms total) ββββββββββββββββββββ
β [+0ms] SELECT * FROM users WHERE id = ? [123] (5ms)
β Connection: mysql, Rows: 1
β
β [+12ms] SELECT * FROM user_settings WHERE user_id = ? [123] (3ms)
β Connection: mysql, Rows: 1
β
β [+25ms] SELECT posts.*, comments.*, likes.* FROM posts
β LEFT JOIN comments ON posts.id = comments.post_id
β LEFT JOIN likes ON posts.id = likes.post_id
β WHERE posts.user_id = ?
β ORDER BY posts.created_at DESC
β LIMIT 10 OFFSET 0 [123] (81ms) β
β Connection: mysql, Rows: 10 (with relationships)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Performance Improvement:
- β 95% faster: From 3,245ms to 156ms
- β 15 queries β 3 queries: Eliminated N+1 problems
- β Fewer rows: Pagination reduces data transfer
- β Indexed queries: All queries using proper indexes
# Compare query performance over time
php artisan chronotrace:list --route="dashboard*" --since="1 hour ago" --format=json | jq '.[] | {timestamp, duration, query_count}'# Find all slow database queries across traces
php artisan chronotrace:list --min-duration=1000 | \
xargs -I {} php artisan chronotrace:replay {} --filter=database --min-duration=100# Check memory usage in traces
php artisan chronotrace:replay slow_001 --memory-analysisββ MEMORY ANALYSIS βββββββββββββββββββββββββββββββββββββββββββββ
β Peak Memory: 45.2MB (at +2,180ms during comments query) β
β Memory Growth: +38MB from start to peak β
β Largest Allocation: comments collection (15.8MB) β
β Recommendation: Use pagination and select specific columns β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Look for queries with high execution time and row counts:
# Queries taking >100ms
php artisan chronotrace:replay trace_id --filter=database --min-duration=100Red flags:
-
SELECTwithWHEREclause taking >50ms - Queries scanning many rows but returning few
-
ORDER BYwithout corresponding index
Common patterns to watch for:
// β Bad: N+1 queries
$users = User::all();
foreach ($users as $user) {
$user->posts->count(); // N+1 query
}
// β
Good: Eager loading with counts
$users = User::withCount('posts')->get();
// β Bad: Loading unnecessary data
$posts = Post::all(); // Loads all columns
// β
Good: Select only needed columns
$posts = Post::select(['id', 'title', 'created_at'])->get();# Analyze cache performance alongside database queries
php artisan chronotrace:replay trace_id --filter=database,cacheLook for:
- Cache misses followed by expensive database queries
- Opportunities to cache query results
- Cache keys that could be optimized
- Enable ChronoTrace recording for target routes
- Generate representative test traffic
- Identify slow requests (>1 second)
- Analyze database events in slow traces
- Count total queries per request
- Identify queries taking >100ms
- Look for N+1 query patterns
- Check for missing indexes (high row scans)
- Verify pagination is used for large datasets
- Add database indexes for slow queries
- Implement eager loading for relationships
- Add pagination for large result sets
- Implement caching for expensive queries
- Re-test and compare performance
- Set up alerts for slow database queries
- Monitor query count trends
- Regular index analysis
- Cache hit rate monitoring
// Add comments to identify query sources
DB::select('SELECT /* Dashboard:user_posts */ * FROM posts WHERE user_id = ?', [$userId]);# In MySQL configuration
slow_query_log = 1
long_query_time = 0.1 # Log queries >100ms-- Use EXPLAIN to analyze query performance
EXPLAIN SELECT * FROM posts WHERE user_id = 123 ORDER BY created_at DESC;// In AppServiceProvider
DB::listen(function ($query) {
if ($query->time > 100) { // Queries >100ms
Log::warning('Slow query detected', [
'sql' => $query->sql,
'bindings' => $query->bindings,
'time' => $query->time
]);
}
});- Basic Usage - Learn fundamental ChronoTrace workflows
- Performance Analysis - Advanced performance debugging
- Configuration - Configure database event capture
- Production Monitoring - Monitor database performance in production
Result: Dashboard loading time reduced from 3.2 seconds to 150ms - a 95% improvement using ChronoTrace to identify and fix database performance bottlenecks!
- Getting Started - Install and configure ChronoTrace
- Examples - Real-world debugging scenarios
- Production Guide - Deploy safely in production
- Troubleshooting - Solve common issues
| Section | Page | Description |
|---|---|---|
| π Basics | Your First Trace | Step-by-step beginner guide |
| ποΈ Config | Recording Modes | Choose when to record traces |
| π‘οΈ Security | Security & PII | Protect sensitive data |
| π§ Tools | Commands | Complete command reference |
- π¬ GitHub Discussions - Community support
- π Report Issues - Bug reports & feature requests
- π§ Contact - Direct support
- π‘ Feature Requests - Suggest improvements
ChronoTrace helps Laravel developers debug applications faster with intelligent request tracing.
Made with β€οΈ by Grazulex β’ Documentation updated August 2024