CodeShot
Seniorسختی 4 از ۵· در 64٪ مصاحبه‌های این حوزه پرسیده شده

مشکل N+1 Query چیست و در EF Core چطور آن را حل می‌کنید؟

نشان کردن

پاسخ کوتاه

وقتی برای هر ردیف از یک لیست، یک کوئری جداگانه برای بارگذاری داده مرتبط اجرا می‌شود؛ راه‌حل اصلی `Include` یا پروجکشن با `Select` است.

پاسخ کامل

اگر ۱۰۰ سفارش بخوانید و سپس در حلقه به order.Customer.Name دسترسی پیدا کنید، EF Core با Lazy Loading برای هر سفارش یک کوئری جدا می‌زند: ۱ کوئری اصلی + ۱۰۰ کوئری اضافه.

سه راه‌حل، به‌ترتیب اولویت:

  1. پروجکشن (Select) — فقط ستون‌های لازم خوانده می‌شوند؛ بهترین گزینه برای خواندن.
  2. Include / ThenInclude — یک JOIN می‌زند و همه چیز را یک‌جا می‌آورد.
  3. AsSplitQuery — وقتی Include باعث انفجار کارتزین می‌شود، آن را به چند کوئری می‌شکند.

بهترین راه تشخیص، لاگ‌کردن SQL تولیدشده است.

مثال کد

// ❌ N+1
var orders = await context.Orders.ToListAsync();
foreach (var order in orders)
    Console.WriteLine(order.Customer.Name);

// ✅ پروجکشن
var rows = await context.Orders
    .Select(o => new { o.Id, CustomerName = o.Customer.Name })
    .ToListAsync();

نکته مهم

در EF Core، Lazy Loading به‌صورت پیش‌فرض غیرفعال است؛ اگر آن را فعال کرده‌اید، احتمال N+1 به‌شدت بالا می‌رود.

اشتباه رایج

❌ استفاده از Include برای چند مجموعه هم‌زمان بدون AsSplitQuery — تعداد ردیف‌های برگشتی ضرب می‌شود و کوئری کند می‌شود.

شرکت‌هایی که این سؤال را پرسیده‌اند

اسنپدیجی‌کالا