Рассмотрим 5 способов как можно значительно ускорить запросы в базу данных вашего проекта на Laravel. Поговорим только о работе Eloquent и Laravel, без основ оптимизации самой таблицы базы данных (индексы, внешние ключи, типы полей…).
1. Используйте Eager loading (жадную загрузку)
При доступе к отношениям Eloquent как к свойствам, связанные модели загружаются «отложенно». Это означает, что данные отношения фактически не загружаются, пока вы впервые не затребуете доступ к свойству. Однако Eloquent может «жадно» загрузить отношения во время запроса родительской модели. Жадная загрузка позволяет избежать проблем «N+1» с запросами. Жадная (edger) загрузка может сократить количество выполняемых запросов за счет предварительной загрузки связанных моделей. Более подробно мы рассказываем здесь.
// Плохой пример (без жадной загрузки)
// Будет выполнен 101 запрос для 100 постов
$posts = Post::all();
foreach ($posts as $post) {
echo $post->author->name;
}
// Хороший пример (с жадной загрузкой)
// Будет выполнено 2 запроса для 100 постов
$posts = Post::with('author')->get();
foreach ($posts as $post) {
echo $post->author->name;
}
2. Кэшируйте запросы
Кэширование часто используемых данных может значительно снизить нагрузку на базу данных.
$posts = Cache::remember('posts', 60, function () {
return Post::all();
});
3. Используйте чанки для большого количества данных или больших таблиц
Разделение на чанки (chunk) позволяет обрабатывать большие наборы данных более мелкими фрагментами, предотвращая переполнение памяти.
Post::chunk(100, function ($posts) {
foreach ($posts as $post) {
// ...
}
});
4. Используйте Eloquent, а не query builder и сырые запросы
Eloquent позволяет писать максимально читаемый код, а изменять функционал приложения с ним несоизмеримо легче. Пишите запросы через функционал Eloquent и перестаньте использовать сырые запросы или конструктор запросов (query builder).
Плохой пример:
SELECT *
FROM `articles`
WHERE EXISTS (SELECT *
FROM `users`
WHERE `articles`.`user_id` = `users`.`id`
AND EXISTS (SELECT *
FROM `profiles`
WHERE `profiles`.`user_id` = `users`.`id`)
AND `users`.`deleted_at` IS NULL)
AND `verified` = '1'
AND `active` = '1'
ORDER BY `created_at` DESC
Хороший пример:
Article::has('user.profile')->verified()->latest()->get();
5. Настройка строгости Eloquent
Laravel предоставляет несколько методов, которые позволяют настраивать поведение Eloquent и «строгость» в различных ситуациях. Метод preventLazyLoading
принимает необязательный булевый аргумент, указывающий, следует ли запретить отложенную загрузку (lazy loading).
Например, вы можете решить отключить отложенную загрузку только в не-продакшн средах, чтобы ваша продакшн среда продолжала функционировать нормально, даже если отложенная загрузка отношения случайно присутствует в рабочем коде. Обычно этот метод следует вызывать в методе boot
сервис-провайдера (AppServiceProvider
) вашего приложения:
// AppServiceProvider.php
use Illuminate\Database\Eloquent\Model;
public function boot(): void
{
Model::preventLazyLoading(!$this->app->isProduction());
}