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، اوآرام، الوکوئنت، اسکیوالالکمی، انتیتی فریمورک کور، بهینهسازی کوئری.