DEV Community

Cover image for Eloquent Performance Patterns: The Ultimate Guide
Ayekple Clemence
Ayekple Clemence

Posted on • Originally published at anansewaa.com

Eloquent Performance Patterns: The Ultimate Guide

Laravel’s Eloquent ORM simplifies database interactions with an expressive syntax, making it one of the easiest tools for managing models and relationships in PHP frameworks. However, inefficient use of Eloquent can lead to performance bottlenecks, such as excessive queries, memory overuse, and slow response times.

With Laravel 12, new features and enhancements have been introduced to optimize Eloquent performance. These updates make it easier to write faster, more efficient queries while keeping your application scalable. In this guide, we’ll explore techniques like eager loading, indexing, query optimization, and caching, using an online office furniture store as a case study.

Let’s unlock the full potential of your Laravel 12 application! 🚀


1. Common Eloquent Performance Bottlenecks

Here are common issues that can impact Eloquent performance:

  • 🔴 N+1 Query Problem — Running multiple queries when fetching related data.
  • 🔴 Large Dataset Retrieval — Fetching too many records, leading to memory issues.
  • 🔴 Unoptimized Queries — Using inefficient relationships, queries, or indexes.
  • 🔴 Excessive Model Instantiation — Creating unnecessary Eloquent models.
  • 🔴 Lack of Database Indexing — Slowing down searches and filtering.

2. Optimizing Query Execution

Pattern 1: Eager Loading to Prevent N+1 Queries

Laravel 12 introduces lazy eager loading improvements, allowing relationships to load dynamically only when needed.

Bad Practice (Lazy Loading)

$orders = Order::all();  
foreach ($orders as $order) {  
    echo $order->customer->name;  // Runs a separate query for each order!
}
Enter fullscreen mode Exit fullscreen mode

👎 Issue: 101 queries for 100 orders (1 for orders + 100 for customers).

Optimized Practice (Eager Loading)

$orders = Order::with('customer')->get();  
foreach ($orders as $order) {  
    echo $order->customer->name;  // Only 2 queries (1 for orders, 1 for customers)
}
Enter fullscreen mode Exit fullscreen mode

Result: Drastically reduces database queries.


Pattern 2: Select Specific Columns (Avoid SELECT *)

Fetching unnecessary columns increases memory usage. Laravel 12 supports column selection in eager loading relationships.

Optimized Practice

$orders = Order::with('customer:id,name')->select('id', 'customer_id', 'total')->get();
Enter fullscreen mode Exit fullscreen mode

Result: Faster execution and lower memory usage.


Pattern 3: Chunking for Large Datasets

Fetching all records at once can cause memory overflow. Laravel 12 enhances chunking with parallel processing support.

Optimized Practice

Order::chunk(500, function ($orders) {
    foreach ($orders as $order) {
        // Process orders in batches of 500
    }
});
Enter fullscreen mode Exit fullscreen mode

Result: Efficiently handles large datasets.


Pattern 4: Caching Queries for Repeated Calls

Laravel 12 introduces query cache tags, enabling better grouping and invalidation of cached queries.

Optimized Practice

$orders = Cache::tags(['orders'])->remember('latest_orders', 60, function () {
    return Order::latest()->take(10)->get();
});
Enter fullscreen mode Exit fullscreen mode

Result: Reduces database hits and improves performance.


3. Optimizing Relationships in Eloquent

Pattern 5: Indexing One-to-Many Relationships

For relationships like "Customer has many Orders," indexing foreign keys improves query speed.

Optimized Practice

Schema::create('orders', function (Blueprint $table) {
    $table->foreignId('customer_id')->constrained()->index();
});
Enter fullscreen mode Exit fullscreen mode

Result: Faster filtering by customer_id.


Pattern 6: Counting Relationships Efficiently

Laravel 12 introduces lazy relationship counts, deferring counting until explicitly needed.

Optimized Practice

$customer = Customer::withCount('orders')->find(1);
echo $customer->orders_count;
Enter fullscreen mode Exit fullscreen mode

Result: Performs COUNT() at the database level for efficiency.


4. Query Optimization Techniques

Pattern 7: Indexing Frequently Queried Columns

Indexes significantly improve query speed for frequently filtered columns.

Optimized Practice

Schema::table('orders', function (Blueprint $table) {
    $table->index('status');  
});
Enter fullscreen mode Exit fullscreen mode

Result: Faster searches by status.


Pattern 8: Avoiding ORDER BY RAND() for Random Records

Bad Practice

$randomProduct = Product::inRandomOrder()->first();
Enter fullscreen mode Exit fullscreen mode

👎 Issue: Slow on large tables.

Optimized Practice

$randomProduct = Product::where('id', '>=', DB::raw('(SELECT FLOOR( MAX(id) * RAND() ) FROM products)'))->first();
Enter fullscreen mode Exit fullscreen mode

Result: Efficient random selection for large datasets.


5. Lazy Loading vs. Eager Loading vs. Query Joins

  • Lazy Loading: Fetches related records only when accessed, leading to multiple queries (N+1 problem).
  • Eager Loading (with()): Fetches related records upfront in fewer queries, ideal for complex reports.
  • Query Joins (join()): Retrieves data in a single SQL query without creating model instances, offering maximum performance.

Example of Using Joins

$orders = Order::join('customers', 'orders.customer_id', '=', 'customers.id')
              ->select('orders.id', 'orders.total', 'customers.name')
              ->get();
Enter fullscreen mode Exit fullscreen mode

Result: Faster than Eloquent relationships for reports and analytics.


Conclusion: Best Practices Summary

  • ✅ Use eager loading (with()) to prevent N+1 queries.
  • ✅ Select only required columns instead of SELECT *.
  • ✅ Use chunk() for large datasets to avoid memory overload.
  • ✅ Cache queries to reduce repeated database hits.
  • ✅ Use withCount() for efficient relationship counts.
  • ✅ Add indexes to foreign keys and frequently queried columns.
  • ✅ Use joins (join()) for reports instead of Eloquent relationships.

By implementing these Eloquent performance patterns and leveraging Laravel 12’s new features, you can optimize your application for high performance. Whether it’s an online office furniture store or any other system, these techniques will make your Laravel app blazing fast. 🚀

Top comments (0)