Eager Loading یا ایگر لودینگ روشی برای بارگیری رابطه‌های لازم همراه با مجموعه اصلی داده است. به جای اینکه برای هر سفارش یک کوئری مجزا برای مشتری اجرا شود، ORM داده‌های مرتبط را با تعداد کوئری کنترل‌شده می‌خواند. ترجمه تحت‌اللفظی این اصطلاح «بارگذاری پیش‌دستانه» است، ولی در گفت‌وگوی فنی معمولاً ایگر لودینگ گفته می‌شود.

مشکل N+1 از کجا می‌آید؟

// N+1: one query for orders, then one per customer
$orders = Order::all();
foreach ($orders as $order) {
    echo $order->customer->name;
}

// Eager loading: fewer database round-trips
$orders = Order::with('customer')->get();

مثلاً برای ۱۰۰ سفارش، حالت اول می‌تواند حدود ۱۰۱ کوئری بسازد. حالت دوم معمولاً یک کوئری برای سفارش‌ها و یک کوئری برای مشتریان مرتبط اجرا می‌کند. این اعداد به ساختار رابطه و وضعیت کش یا ORM وابسته‌اند.

متدهای مهم لاراول

متدکاربردنمونه
withپیش از اجرای کوئری، رابطه را مشخص می‌کندOrder::with('customer')->get()
loadروی مدل یا کالکشن دریافت‌شده رابطه را می‌خواند$orders->load('items')
loadMissingفقط رابطه‌ای را بارگذاری می‌کند که هنوز Load نشده$order->loadMissing('customer')
withCountتعداد رابطه را بدون بارگذاری کامل اعضا می‌آوردOrder::withCount('items')->get()
loadCountتعداد رابطه را پس از دریافت مدل می‌آورد$order->loadCount('items')
withWhereHasفیلتر مدل و ایگر لودینگ رابطه با یک شرطUser::withWhereHas('posts', fn ($q) => $q->where('active', 1))->get()

نمونه در Python با Django

# ForeignKey: SELECT with JOIN
orders = Order.objects.select_related('customer').all()
# Reverse or many-to-many relationships: prefetch
orders = Order.objects.prefetch_related('items').all()

نمونه در Python با SQLAlchemy

from sqlalchemy import select
from sqlalchemy.orm import selectinload
stmt = select(Order).options(selectinload(Order.items))
orders = session.scalars(stmt).all()

نمونه در ASP.NET Core با EF Core

var orders = await db.Orders
    .Include(o => o.Customer)
    .Include(o => o.Items)
    .AsNoTracking()
    .ToListAsync();

در Go چطور؟

کتابخانه استاندارد Go یک ORM با ایگر لودینگ داخلی ندارد. در GORM از Preload استفاده می‌شود، و در database/sql می‌توان خودمان داده مرتبط را با Batch Query یا Join بخوانیم.

// GORM example
var orders []Order
err := db.Preload("Customer").Preload("Items").Find(&orders).Error

نکته فنی

ایگر لودینگ بیش از حد هم مناسب نیست. بارگذاری چند رابطه حجیم یا چند Join ممکن است حافظه و حجم داده را بالا ببرد. تعداد و اندازه کوئری‌ها را اندازه‌گیری کنید.

اصطلاحات مرتبط: مشکل کوئری N+1، او‌آر‌ام، الوکوئنت، اس‌کیوال‌الکمی، انتیتی فریم‌ورک کور، بهینه‌سازی کوئری.