Глобальное предотвращение проблемы N+1 в Laravel с автоматической жадной загрузки

Жадная загрузка в Laravel — это способ загрузки связанных моделей при запросе к модели. Она сделана для предотвращения проблемы N+1, возникающей, при загрузке модели и последующей поочерёдной загрузке связанных с ней моделей, что приводит к многочисленным запросам к базе данных.

Проблема N+1 может стать проблемой производительности, если много связанных моделей. Жадная загрузка позволяет загрузить все связанные модели в одном запросе, что может значительно повысить производительность.

Например, если есть модель User, содержащая множество моделей Post, то можно выполнить жадную загрузку сообщений следующим образом:

$users = User::with('posts')->get();

foreach ($users as $user) {
// Это не приведёт к выполнению отдельного запроса для каждого пользователя
echo $user->posts->title;
}

В данном случае загрузятся все пользователи и их сообщения в одном запросе, вместо загрузки сообщения каждого пользователя по одному.

$users = User::all();

foreach ($users as $user) {
// Это приведёт к выполнению отдельного запроса для каждого пользователя
echo $user->posts->title;
}

В этом случае возникнет проблема N+1, когда один запрос загружает всех пользователей, а затем один запрос для каждого пользователя загружает его сообщение.

Это замечательно, но, как вы можете заметить, жадная загрузка не всегда является поведением по умолчанию в Laravel. Необходимо явно указать Laravel на жадную загрузку связанных моделей с помощью метода with().

Для исправления этой ситуации в Laravel появилась возможность глобально включить жадную загрузку, автоматически загружающую связанные модели.

Глобальная автоматическая жадная загрузка

В Laravel 12.x появился новый метод automaticallyEagerLoadRelationships() для класса Model. Этот метод позволяет включить автоматическую жадную загрузку всех моделей в приложении.

Включить эту функцию можно, добавив следующий код в AppServiceProvider:

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Model::automaticallyEagerLoadRelationships();
}
}

Таким образом, теперь даже код с проблемой N+1, продемонстрированный ранее, будет работать без каких-либо проблем.

// Поскольку автоматическая жадная загрузка включена глобально,
// этот код будет работать без возникновения проблемы с N+1
$users = User::all();

foreach ($users as $user) {
echo $user->posts->title;
}

Автоматическая жадная загрузка моделей

Если не хотите включать автоматическую жадную загрузку глобально, можно включить её для отдельной модели. Для этого необходимо добавить в модель метод automaticallyEagerLoadRelationships() следующим образом.

use App\Models\User;

User::automaticallyEagerLoadRelationships();

Автоматическая жадная загрузка запросов

И наконец, можно включить автоматическую жадную загрузку на основе отдельного запроса. Для этого необходимо использовать метод withRelationshipAutoloading(), как показано ниже.

$users = User::all()->withRelationshipAutoloading();

foreach ($users as $user) {
echo $user->posts->title;
}

Заключение

Я думаю, что это отличная функциональная возможность в Laravel и потенциальное спасение для новичков, не знакомых с жадной загрузкой.

Подробнее об этой функции вы можете прочитать в PR: [12.x] Added Automatic Relation Loading (Eager Loading) Feature #53655

Комментарии


Дополнительные материалы

Предыдущая Статья

Разноцветное выделение в CSS

Следующая Статья

Расширенное использование attr() в CSS