مقاله

with()، load()، lazy eager loading و count — چطور N+1 را در Eloquent پیدا و حل کنیم با مثال Post، Category و User.

Eager Loading در Laravel — راهنمای کامل رفع N+1 Query

Eager Loading در Laravel — راهنمای کامل رفع N+1 Query

صفحه لیست مقالات ۲۰۰ میلی‌ثانیه طول می‌کشد؛ همان صفحه با N+1 ناگهان ۲ ثانیه می‌شود — مشتری نمی‌فهمد، فقط «سایت کند است». در ۷۰٪ code reviewهای junior، N+1 اولین گلوگاه است. خبر خوب: در Eloquent با with() حل می‌شود اگر relation درست تعریف شده باشد.

N+1 دقیقاً چیست؟

۱ query برای لیست Post + N query برای category هر post = N+1. در Blade:

@foreach($posts as $post)
  {{ $post->category->name }}
@endforeach

بدون eager load، هر iteration یک SELECT به categories می‌زند.

راه‌حل: with()

$posts = Post::query()
    ->with(['category:id,name,slug', 'user:id,name'])
    ->published()
    ->latest()
    ->paginate(15);

فقط ستون‌های لازم را در nested select بیاورید — memory کمتر.

چند سطح تودرتو

Post::with(['comments.user', 'tags'])->get();

withCount — بدون بارگذاری همه رکوردها

Category::withCount('posts')->orderByDesc('posts_count')->get();

برای badge «تعداد مقاله» روی دسته عالی است.

load() و loadMissing()

اگر قبلاً collection دارید:

$posts->load('category');
$posts->loadMissing('tags');

Lazy Eager Loading (Laravel 8+)

Model::preventLazyLoading(! app()->isProduction());

// یا در AppServiceProvider boot — فقط dev

در development exception می‌گیرید اگر relation بدون with لود شود — عادت خوب می‌سازد.

تشخیص N+1

  • Laravel Debugbar — تب queries
  • Telescope
  • DB::listen() در local
  • MySQL slow query log

جزئیات بیشتر: بهینه‌سازی کوئری.

API و Resource

// PostResource — whenLoaded
'category' => CategoryResource::make($this->whenLoaded('category')),

از serialize کردن relation لودنشده جلوگیری کنید.

whereHas بدون eager

فیلتر relation تعداد query را زیاد می‌کند — بعد از فیلتر with بزنید:

Post::whereHas('tags', fn ($q) => $q->where('slug', 'laravel'))
    ->with('tags')
    ->get();

اشتباهات

  • with() روی relation تعریف‌نشده
  • over-eager: لود relation استفاده‌نشده
  • فراموش pagination با with سنگین

جمع‌بندی

قبل از merge هر لیستی در view، بپرسید: چه relationهایی نمایش داده می‌شود؟ همان‌ها with. روابط، Scope.

بهینه‌سازی پروژه