Работая с Laravel Eloquent, одна из самых частых проблем производительности — это N+1 запросов. Кроме того, правильное использование кэширования может значительно ускорить работу приложения. В этой статье мы разберём конкретные приёмы оптимизации с примерами кода.
1. Проблема N+1
N+1 запросов возникает, когда вы загружаете коллекцию моделей и для каждой модели выполняете отдельный запрос к связанной таблице.
Пример:
$posts = App\Models\Post::all();foreach ($posts as $post) {
echo $post->author->name; // каждый раз отдельный запрос к таблице users
}
Если у нас 100 постов, то Eloquent выполнит 1 запрос для постов + 100 запросов для авторов, что резко замедляет приложение.
2. Решение: eager loading (with)
Eloquent позволяет заранее загружать связанные модели через eager loading:
$posts = App\Models\Post::with('author')->get();foreach ($posts as $post) {
echo $post->author->name; // авторы уже загружены в 1 запрос
}
Результат: 2 запроса вместо 101: один для постов и один для всех авторов.
2.1. Nested eager loading
Если есть вложенные связи:
$comments = App\Models\Comment::with('post.author')->get();foreach ($comments as $comment) {
echo $comment->post->author->name;
}
Eloquent выполнит всего 3 запроса, независимо от количества комментариев.
2.2. Ограничение полей (select)
Чтобы уменьшить нагрузку на базу, можно выбирать только нужные поля:
$posts = App\Models\Post::with('author:id,name')->get();
Теперь подгружается только id и name автора, а не вся модель.
3. Кэширование запросов
Даже после устранения N+1, тяжелые запросы можно кэшировать.
3.1. Кэш на уровне запроса
use Illuminate\Support\Facades\Cache;$posts = Cache::remember('posts_with_authors', 60, function () {
return App\Models\Post::with('author')->get();
});
- Ключ
posts_with_authorsхранится в кэше 60 минут. - При следующем запросе данные будут взяты из кэша без нагрузки на БД.
3.2. Кэширование отдельных моделей
Можно кэшировать конкретные модели:
$post = Cache::remember("post_{$id}", 30, function () use ($id) {
return App\Models\Post::with('author')->find($id);
});
Такой подход полезен для популярных страниц или часто запрашиваемых ресурсов.
4. Дополнительные приёмы оптимизации
- Lazy eager loading — загружать связи только при необходимости:
$posts = App\Models\Post::all();
$posts->load('author'); // делает 1 запрос для всех авторов
- Chunking — обработка больших наборов данных партиями:
App\Models\Post::chunk(100, function ($posts) {
foreach ($posts as $post) {
echo $post->title;
}
});
- Использование
joinвместоwith, если не нужна модель, а только данные:
$posts = App\Models\Post::join('users', 'posts.author_id', '=', 'users.id')
->select('posts.*', 'users.name as author_name')
->get();
5. Вывод
- N+1 запросы — одна из главных причин тормозов Eloquent. Используйте
with()иload()для их устранения. - Ограничивайте поля при загрузке связей через
select. - Кэширование на уровне запросов или моделей ускоряет повторные выборки.
- Chunking и join-запросы помогают при больших объёмах данных.
С этими приёмами ваше приложение будет работать быстрее, стабильнее и эффективнее.


Добавить комментарий