Устранение N+1 запросов на этапе разработки
Проблема N+1 запросов довольно частая и в некоторой степени снижает производительность приложения при работе с большими списками. К сожалению, не всегда удаётся выявить такие места особенно в больших приложениях и, тем более, если в них нет тестов. Но как исправить эту проблему, выявив все такие места? На самом деле это сделать очень легко! Достаточно в сервис-провайдере написать такой код:
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;
class ModelServiceProvider extends ServiceProvider
{
public function boot(): void
{
Model::preventLazyLoading(
! $this->app->isProduction()
);
}
}
Да, это всё. Но что он делает?
Метод preventLazyLoading позволяет отслеживать обращение к релейшенам и, если они не были загружены при помощи жадной загрузки, то выбросит эксепшен. Например:
$pages = Page::get();
$pages->first()->images;
Illuminate\Database\LazyLoadingViolationException:
Attempted to lazy load [images] on model [App\Models\Page] but lazy loading
is disabled.
Устранить проблему легко! Достаточно указать жадную загрузку:
$pages = Page::query()
->with(['images'])
->get();
$pages->first()->images;
Теперь ошибки не будет.
Но как же с продакшеном? – спросите. И там всё очень просто! Указав в сервис провайдере ! $this->app->isProduction()
мы гарантируем что данная проверка будет запускаться на любом окружении кроме продакшена. За это отвечает параметр APP_ENV
в файле .env
.
Вот и всё.