N+1 in SQL

What the N+1 Problem Looks Like in SQL

Relationships load lazily: Order::get() fetches orders only, and each $order->customer read sends its own SELECT. One query for the list plus one per row is the N+1 pattern:

Lazy loading a belongsTo inside a loopSQL
use App\Models\Order;
DB::listen(fn ($query) => print('-- '.$query->toRawSql().PHP_EOL));
$orders = Order::where('status', 'shipped')->orderBy('id')->limit(3)->get();
foreach ($orders as $order) {
    echo "order {$order->id}: {$order->customer->name}\n";
}
Output
-- select * from `orders` where `status` = 'shipped' order by `id` asc limit 3
-- select * from `customers` where `customers`.`id` = 1 limit 1
order 1: Ana Souza
-- select * from `customers` where `customers`.`id` = 2 limit 1
order 2: Ben Carter
-- select * from `customers` where `customers`.`id` = 1 limit 1
order 4: Ana Souza

Each query runs on first access, and Ana Souza is fetched twice because sibling models share nothing. No query is visible in the code, which is why N+1 survives code review.

Lazy loading sends one query per parent row; eager loading one per relationship
Lazy loading sends one query per parent row; eager loading one per relationship

A JOIN would answer in one statement but repeat the customer columns on every order row. Eloquent's eager loading instead sends one WHERE ... IN (...) query per relationship and matches in memory, so the count no longer grows with the rows.