Жадная загрузка и проблема N+1
Проблема N+1
Когда ты обращаешься к связи внутри цикла, Eloquent выполняет отдельный запрос на каждую запись:
$posts = Post::all(); // 1 запрос
foreach ($posts as $post) {
echo $post->user->name; // N запросов
}
Если постов 100 — будет 101 запрос. Это медленно.
Решение: with
Метод with загружает связи заранее, одним дополнительным запросом:
$posts = Post::with('user')->get(); // 2 запроса
foreach ($posts as $post) {
echo $post->user->name; // без запросов
}
Вложенная загрузка
Post::with('user', 'comments.user')->get();
Или через точку:
Post::with('comments.user')->get();
Загрузка с условием
Post::with(['comments' => function ($query) {
$query->where('approved', true)->latest();
}])->get();
Подсчёт связанных
Post::withCount('comments')->get();
foreach ($posts as $post) {
echo $post->comments_count;
}
С условием:
Post::withCount(['comments' => function ($query) {
$query->where('approved', true);
}])->get();
Суммы и агрегаты
Post::withSum('orders', 'total')->get();
Post::withAvg('ratings', 'score')->get();
Post::withMax('views', 'count')->get();
Ленивая загрузка после получения
$posts = Post::all();
$posts->load('user', 'comments');
Предотвращение ленивой загрузки
В AppServiceProvider:
use Illuminate\Database\Eloquent\Model;
public function boot(): void
{
Model::preventLazyLoading(!app()->isProduction());
}
Теперь при ленивой загрузке в dev-режиме будет исключение.