Laravels Eloquent ORM is great for walking relationships and just getting the job done. But it comes at a price without planning each relationship walked can generate more queries against your database, while with a bit of upfront planning the child relationships can be fetched and hydrated into models in the same query as the parent resource. Which can drastically increase performance, and in the days of serverless/auto-scaling databases often charging by query volume also reduce costs.
So how do I detect where N+1 queries slipped through in development?
In your Laravel project open AppServiceProvider
and add this code, which will
make Laravel throw a Illuminate\Database\LazyLoadingViolationException
every
time a relationship is lazy loaded in non-production environments.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
// ...
Model::preventLazyLoading(! app()->isProduction());
// ...
}
}
How do you fix the queries? Use the with
method with you Eloquent queries.
e.g. instead of
$post = Post::find($id);
echo $post->author->name;
preload the author with
$post = Post::with('author')->find($id);
echo $post->author->name;