Eager Loading / Lazy Loading

Optimizing queries with Eager Loading

graph TD A[Lazy Loading] --> B[1 Query: Get Users] B --> C[Loop Through Users] C --> D[N Queries: Get Posts for Each User] E[Eager Loading] --> F[1 Query: Get Users] F --> G[1 Query: Get All Posts] G --> H[Loop Through Users with Preloaded Posts]

Eager Loading and Lazy Loading are two different methods for loading relationships in Eloquent. Choosing correctly between these two can greatly affect application performance.


Lazy Loading (Default):


Lazy Loading means relationships are only loaded when you access them. This is the default behavior of Eloquent.


N+1 Query Problem:


When you lazy load relationships and use them in a loop, an additional query is executed for each parent record. This causes N+1 query problem:


  • 1 query for parent records
  • N queries for relationships (one query per parent)

Eager Loading (Solution):


Eager Loading means relationships are preloaded. Using with(), all relationships are loaded in one or a few queries.


Benefits of Eager Loading:


  • <strong>Performance</strong>: Reducing queries from N+1 to 2-3 queries
  • <strong>Efficiency</strong>: Better use of database resources
  • <strong>Scalability</strong>: Better for large datasets
  • <strong>Memory</strong>: Better memory usage

Use Cases:


  • Relationships used in loops
  • Relationships displayed in views
  • API responses that include relationships
  • Reports and analytics queries

Examples

Lazy Loading (N+1 Problem)

<?php

// Lazy Loading - N+1 Problem
$users = User::all(); // 1 query

foreach ($users as $user) {
    echo $user->posts->count(); // N queries (one per user)
    // Total: 1 + N queries
}

// If you have 100 users, this executes 101 queries!

Lazy loading that causes N+1 query problem.

Eager Loading (Solution)

<?php

// Eager Loading - Solution
$users = User::with('posts')->get(); // 2 queries total
// Query 1: SELECT * FROM users
// Query 2: SELECT * FROM posts WHERE user_id IN (1,2,3,...)

foreach ($users as $user) {
    echo $user->posts->count(); // No additional queries
    // Total: 2 queries regardless of number of users
}

Eager loading that solves N+1 problem.

Multiple Relationships

<?php

// Eager load multiple relationships
$users = User::with(['posts', 'profile', 'roles'])->get();
// 4 queries total:
// 1. Users
// 2. Posts
// 3. Profiles
// 4. Roles

// Nested eager loading
$users = User::with('posts.comments')->get();
// Loads users, their posts, and comments on those posts

// Multiple nested
$users = User::with([
    'posts.comments',
    'posts.tags',
    'profile'
])->get();

Eager loading multiple relationships and nested relationships.

Eager Loading with Constraints

<?php

// Eager load with constraints
$users = User::with(['posts' => function ($query) {
    $query->where('published', true)
          ->orderBy('created_at', 'desc');
}])->get();

// Eager load with count
$users = User::withCount('posts')->get();
// Adds posts_count attribute

// Eager load with exists
$users = User::withExists('posts')->get();
// Adds posts_exists attribute

// Eager load with min/max/avg/sum
$users = User::withAvg('posts', 'views')->get();
// Adds posts_avg_views attribute

Eager loading with constraints and aggregate functions.

Lazy Eager Loading

<?php

// Load relationships after model is retrieved
$users = User::all();

// Later, eager load relationships
$users->load('posts');

// Or load for specific models
$users->loadMissing('posts');

// Conditional lazy eager loading
if ($needsPosts) {
    $users->load('posts');
}

Lazy eager loading that loads relationships after model is retrieved.

Preventing Lazy Loading

<?php

// Prevent lazy loading in development
// In AppServiceProvider
Model::preventLazyLoading(! app()->isProduction());

// This will throw exception if lazy loading is attempted
$user = User::find(1);
$posts = $user->posts; // Throws exception in development

// Must use eager loading
$user = User::with('posts')->find(1);
$posts = $user->posts; // OK

Preventing lazy loading in development to catch N+1 problems.

Eager Loading Performance Tips

<?php

// Select specific columns
$users = User::with('posts:id,user_id,title')->get();

// Eager load with select
$users = User::with(['posts' => function ($query) {
    $query->select('id', 'user_id', 'title', 'created_at');
}])->get();

// Use chunking with eager loading
User::with('posts')->chunk(100, function ($users) {
    foreach ($users as $user) {
        // Process user with preloaded posts
    }
});

Performance tips for eager loading.

Use Cases

  • Preventing N+1 query problem
  • Optimizing queries with relationships
  • Improving performance in loops
  • API responses with relationships
  • Reports and analytics queries
  • Views that display relationships

Common Mistakes

  • Forgetting eager loading in loops
  • Using lazy loading for relationships used in views
  • Eager loading relationships that aren't used
  • Forgetting nested relationships
  • Using eager loading for single records
  • Eager loading with large datasets without chunking

Best Practices

  • Always use eager loading for relationships in loops
  • Use with() for relationships used in views
  • Use nested eager loading for deep relationships
  • Use withCount() for counting relationships
  • Use select() for selecting specific columns
  • Use preventLazyLoading() in development
  • Apply eager loading only for relationships that are used

Edge Cases

  • Eager loading with very large datasets
  • Nested eager loading with multiple levels
  • Eager loading with polymorphic relationships
  • Eager loading in queue jobs
  • Lazy loading with conditional access
  • Eager loading with complex constraints

Performance Notes

  • Eager loading can solve N+1 problem
  • Use select() for selecting specific columns
  • Use withCount() instead of loading relationships for counts
  • Use chunking for large datasets
  • Eager loading overhead is very low
  • Use indexes for foreign keys

Security Notes

  • Ensure eager loaded relationships are authorized
  • Use constraints for filtering sensitive relationships
  • Ensure eager loading doesn't expose sensitive data

Interview Points

  • What is N+1 query problem and how is it solved?
  • What is the difference between eager loading and lazy loading?
  • How can you eager load multiple relationships?
  • What is withCount() and when is it used?
  • How can you prevent lazy loading?
  • When should you use eager loading?

Version Notes

  • Laravel 11.x: Improved performance in eager loading
  • Laravel 11.x: Better support for nested eager loading
  • Laravel 10.x: Improved preventLazyLoading()
  • Laravel 9.x: Improved withCount() performance