Разработчикам

7 уровней оптимизации Laravel: от новичка до мастера-фокусника

Эдгар Косулин 2 мин чтения

Как сэкономить до 98% ресурсов, или как превратить простой Laravel-код в магию, которую мало кто осмелится трогать?

Готовьтесь: мы отправимся в увлекательное путешествие по ступеням оптимизации в Laravel. От наивного «лишь бы всё работало» до уверенного «коллеги либо назовут вас волшебником, либо обвинят в шаманстве». Поехали!

Уровень 1: Первый шаг: жадная загрузка (Eager Loading)

Всё начинается с классики. Вы только-только узнали, что такое with(), и чувствуете себя героем: никакого N+1, только два запроса, и все данные под рукой.

use App\Models\Post;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
    $posts = Post::with('user')->get();
    return view('posts', ['posts' => $posts]);
});

Результат: Для 100k постов затрачиваем 191 МБ и примерно 0,63 сек. Итоговый «коэффициент ресурсоёмкости»: 120 единиц (условно). Неплохо, но не идеально.

Уровень 2: Первые серьёзные шаги. «А точно ли нужны все эти поля?»

Далее вы задумались: зачем вытаскивать всё подряд? Ограничьте выборку до нужных столбцов, и уже почувствуете разницу.

use App\Models\Post;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
    $posts = Post::with('user:id,name')
                 ->select('id','user_id','title')
                 ->get();
    return view('posts', ['posts' => $posts]);
});

Результат: Минус 20% ресурсоёмкости. Конечно, вы ещё не спасли мир, но уже выглядите более профессионально.

Уровень 3: Переход на ручное управление, разделяем запросы

Теперь вы идёте дальше. Вместо жадной загрузки два отдельных запроса: один для постов, другой для пользователей. В итоге вы создаёте своего рода таблицу соответствий.

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
    $posts = Post::select('id','user_id','title')->get();
    $users = User::whereIn('id', $posts->pluck('user_id')->unique())
                 ->pluck('name', 'id');
    return view('posts', ['posts' => $posts, 'users' => $users]);
});

Результат: Ещё +15% эффективности. Вы уже пьёте кофе с лёгкой улыбкой превосходства.

Уровень 4: Попытка хитрить с distinct

Вы пытаетесь доверить часть оптимизации базе данных: пусть она сама выберет уникальные значения user_id. Результаты? Есть прирост по времени, но с памятью особого выигрыша нет.

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
    $query = Post::query();
    $posts = (clone $query)->select('id', 'user_id', 'title')->get();
    $users = User::whereIn('id', (clone $query)->select('user_id')->distinct())
                 ->get();
    return view('posts', ['posts' => $posts, 'users' => $users]);
});

Результат: Быстрее, но ощутимого облегчения памяти нет. Что ж, оптимизация - это путь проб и ошибок.

Уровень 5: Скрытая магия toBase()

Вы обнаружили toBase(), который пропускает всю «магию» Eloquent, оставляя только «чистые» результаты. И вот тут начинается серьёзный прорыв.

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
    $query = Post::query();
    $posts = (clone $query)->select('id','user_id','title')
                           ->toBase()
                           ->get();
    $users = User::whereIn('id', (clone $query)->select('user_id')->distinct())
                 ->toBase()
                 ->get();
    return view('posts', ['posts' => $posts, 'users' => $users]);
});

Результат: Минус 85% ресурсоёмкости. Теперь вы чувствуете себя настоящим гуру Laravel.

Уровень 6: Ещё шаг: chunkById

Время применить «чанкование». Вы загружаете данные порционно и аккуратно складываете их в коллекцию. К примеру, по 15 000 записей.

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
    $query = Post::query();
    $posts = collect();
    (clone $query)->select('id', 'user_id', 'title')
                  ->toBase()
                  ->orderBy('posts.id')
                  ->chunkById(15000, function ($collection) use (&$posts) {
                      $posts->push(...$collection);
                  }, 'id');
    $users = User::whereIn('id', (clone $query)->select('user_id')->distinct())
                 ->toBase()
                 ->get();
    return view('posts', ['posts' => $posts, 'users' => $users]);
});

Результат: Ещё плюс 14% к оптимизации. Кажется, вы уже приблизились к пределу.

Уровень 7: Высший пилотаж: Lazy Collections

Финальный козырь в рукаве: lazyById(). Представьте себе chunkById, но более «ленивый» и гибкий. Вы загружаете данные партиями (например, по 10 000), удерживая их в памяти по мере необходимости.

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
    $query = Post::query();
    $users = User::whereIn('id', (clone $query)->select('user_id')->distinct())
                 ->pluck('name', 'id');
    $posts = (clone $query)
                 ->select('id', 'user_id', 'title')
                 ->toBase()
                 ->lazyById(10000, 'id');
    return view('welcome', [
        'posts' => $posts,
        'users' => $users,
    ]);
});

Результат: Память используется ещё более экономно. Вы стоите на вершине горы оптимизации, смотрите свысока на затраты ресурсов и понимаете, что сократили их примерно на 98% (с 120 до 2,4). Ваши коллеги в шоке: либо восхищены, либо озадачены тем, что вы сотворили.

Итог:

Вы прошли путь от новичка, довольствующегося eager loading, до мастера, выжимающего из Laravel максимум. Но не забывайте, с чего вы начинали. И не удивляйтесь, если через секунду ваш начальник влетит с вопросом: «А как там прогресс по остальным задачам?» Вы сэкономили серверные ресурсы, но кто сэкономит ваше время теперь?

Laravel PHP

Поделиться: Telegram ВКонтакте

Новые статьи и разборы — в канале Siteko: Telegram MAX

Подписчикам: +30 дней к пробному хостингу, клиентам: +150 ₽ на баланс

Пошаговые инструкции по нашим услугам — в базе знаний

Ещё по теме

Разработчикам 5 мин чтения

Laravel 13: нововведения и улучшения

Laravel 13 вышел 17 марта 2026 года: Тейлор Отвелл представил релиз на Laracon EU. Если вы привыкли к тому, что мажорные версии Laravel приносят болезненные миграции, этот релиз вас приятно удивит: команда сознательно сделала ставку на минимум ломающих изменений и максимум практической пользы. Больш...