/laravel-agent:db:optimize
Analyze and optimize database queries and schema
Overview
The /db:optimize command analyzes your Laravel application's database queries and schema to identify performance bottlenecks and optimization opportunities. It scans for N+1 queries, Big O complexity issues, missing indexes, slow queries, and suggests eager loading strategies to improve database performance.
Usage
/laravel-agent:db:optimize [target]
Examples
# Analyze entire application
/laravel-agent:db:optimize
# Analyze specific controller
/laravel-agent:db:optimize OrderController
# Analyze specific table
/laravel-agent:db:optimize orders
What Gets Analyzed
The command performs a comprehensive database optimization analysis:
| Analysis Type | What It Checks | What It Suggests |
|---|---|---|
| N+1 Queries | Loops that trigger additional queries per iteration | Eager loading with with() or load() |
| Big O Issues | Nested loops O(n²), contains() in loops, in-loop queries |
groupBy(), keyBy(), flip()->has() for O(1) lookups |
| Missing Indexes | Columns used in WHERE, JOIN, and ORDER BY clauses | Index creation migrations |
| Slow Queries | Queries with high execution time or complexity | Query rewriting or caching strategies |
| Eager Loading | Relationship access patterns in controllers/models | Optimal eager loading strategies |
| Schema Efficiency | Table structure, column types, and constraints | Schema improvements and normalization |
Optimization Process
The command follows a systematic approach to database optimization:
- Scan for N+1 queries - Identifies loops and iterations that trigger multiple database queries
- Detect Big O complexity issues - Finds O(n²) patterns like nested loops and inefficient lookups
- Check missing indexes - Analyzes query patterns to find columns that would benefit from indexing
- Analyze slow queries - Reviews query complexity and execution time
- Suggest eager loading - Recommends optimal relationship loading strategies
- Review schema efficiency - Evaluates table structure and suggests improvements
Example: N+1 Query Detection
Before optimization:
<?php
// Controller with N+1 problem
public function index()
{
$orders = Order::all();
foreach ($orders as $order) {
echo $order->customer->name; // N+1 query!
echo $order->items->count(); // Another N+1!
}
}
After optimization:
<?php
// Optimized with eager loading
public function index()
{
$orders = Order::with(['customer', 'items'])->get();
foreach ($orders as $order) {
echo $order->customer->name; // Uses eager loaded data
echo $order->items->count(); // No additional query
}
}
Example: Big O Complexity Detection
Before optimization (O(n²)):
<?php
// O(n²) - Nested loop comparing all items
$users = User::all();
$orders = Order::all();
foreach ($users as $user) {
foreach ($orders as $order) {
if ($order->user_id === $user->id) {
// Process - runs n×m times!
}
}
}
// O(n²) - contains() is O(n), called n times
$existingEmails = User::pluck('email');
foreach ($newUsers as $userData) {
if (!$existingEmails->contains($userData['email'])) {
User::create($userData);
}
}
After optimization (O(n)):
<?php
// O(n) - Eager load relationships
$users = User::with('orders')->get();
foreach ($users as $user) {
foreach ($user->orders as $order) {
// Process - each order accessed once
}
}
// Or: O(n) - Use groupBy for O(1) lookups
$ordersByUser = Order::all()->groupBy('user_id');
foreach ($users as $user) {
$userOrders = $ordersByUser->get($user->id, collect());
}
// O(n) - Use flip() for O(1) has() lookups
$existingEmails = User::pluck('email')->flip();
foreach ($newUsers as $userData) {
if (!$existingEmails->has($userData['email'])) {
User::create($userData);
}
}
Example: Missing Index Detection
Before optimization:
<?php
// Query without index
$orders = Order::where('status', 'pending')
->where('user_id', $userId)
->orderBy('created_at', 'desc')
->get();
Generated migration:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::table('orders', function (Blueprint $table) {
// Composite index for common query pattern
$table->index(['status', 'user_id', 'created_at']);
});
}
public function down()
{
Schema::table('orders', function (Blueprint $table) {
$table->dropIndex(['status', 'user_id', 'created_at']);
});
}
};
Target Scopes
You can scope the optimization analysis to specific parts of your application:
- Entire Application - Run without arguments to analyze all controllers, models, and queries
- Specific Controller - Pass a controller name to focus on its query patterns
- Specific Table - Pass a table name to analyze its schema and related queries
- Specific Model - Pass a model name to review its relationships and query usage
Best Practices
- Run regularly - Make database optimization part of your development workflow
- Start with N+1 queries - These often provide the biggest performance wins
- Test index suggestions - Not all indexes improve performance; test on production-like data
- Monitor query counts - Use Laravel Debugbar or Telescope to verify improvements
- Consider caching - Some queries may be better cached than optimized
- Profile before and after - Measure actual performance improvements
Performance Impact
Typical optimization results:
- N+1 fixes - Can reduce query count from hundreds to single digits
- Big O fixes - Convert O(n²) to O(n), massive improvements for large datasets
- Index additions - Often improve query speed by 10-100x
- Eager loading - Reduces page load time by 50-90% in data-heavy views
- Schema optimization - Improves storage efficiency and join performance
Related Agent
This command uses the laravel-database agent.
See Also
- /laravel-agent:db:migration - Create database migrations
- /laravel-agent:model:make - Generate models with relationships
- laravel-database skill - Auto-invoked for database operations