شکار N+1ها و از بین بردن کوئری‌های هدر رفته در Laravel

کارهای مربوط به عملکرد (Performance) اغلب خسته‌کننده هستند.

همیشه بحث داستان‌های قهرمانانه نیست که در آن‌ها تأخیر (latency) را ۸۰٪ کاهش می‌دهید. بیشتر روزها، موضوع فقط پاکسازی است. کوئری‌هایی را پیدا می‌کنید که نمی‌دانستید در حال اجرا هستید، و سپس آن‌ها را حذف می‌کنید.

اگر اپلیکیشن Laravel شما در حال رشد است، احتمالاً با این سه مشکل روبرو هستید.

۱. کوئری‌های پنهان N+1

چیزی را که نمی‌بینید، نمی‌توانید اصلاح کنید. در محیط محلی (local) خود از ابزاری مانند beyondcode/laravel-query-detector استفاده کنید. این ابزار به شما می‌گوید چه زمانی از الگوی loop-and-lazy-load استفاده می‌کنید.

این را در محیط production اجرا نکنید، زیرا باعث ایجاد بار اضافی (overhead) می‌شود. آن را فقط زمانی ثبت کنید که اپلیکیشن شما در حالت local یا testing باشد.

۲. اتلاف در Eager Loading

افراد اغلب مشکلات N+1 را با اضافه کردن with() حل می‌کنند، اما این کار مشکل جدیدی ایجاد می‌کند. ممکن است رابطه‌ای را eager-load کنید که ویو (view) شما دیگر از آن استفاده نمی‌کند.

اگر یک بازطراحی باعث حذف یک ستون از جدول شود، باید فراخوانی with() مربوطه را در کنترلر خود حذف کنید. شما دارید هزینه داده‌هایی را می‌پردازید که دور می‌ریزید.

با هر eager load مانند یک ادعا (claim) برخورد کنید. اگر از داده‌ها استفاده نمی‌کنید، آن ادعا را حذف کنید.

۳. محاسبه مجدد داده‌های یکسان

برخی مقادیر در طول کل درخواست ثابت می‌مانند. اگر آن‌ها را چندین بار محاسبه کنید، منابع CPU را هدر می‌دهید. برای حل این مشکل از memoization استفاده کنید.

مثال:

protected ?string $defaultConnection = null;

public function getDefaultConnectionName(): string
{
    return $this->defaultConnection ??= $this->resolveDefaultConnection();
}

عملگر ??= مقدار را یک بار محاسبه کرده و در بقیه درخواست از آن مجدداً استفاده می‌کند.

۴. تله‌های کوئری در داشبورد

داشبوردها اغلب برای هر کارت یک کوئری count() جداگانه اجرا می‌کنند. اگر شش کارت داشته باشید، شش کوئری اجرا می‌شود.

در عوض، این دو کار را انجام دهید:

  • شمارش‌ها را گروه‌بندی کنید. تمام مجموع‌ها را برای یک جدول در یک کوئری واحد دریافت کنید.
  • از یک کش (cache) کوتاه استفاده کنید. آمار داشبورد نیازی ندارد که ثانیه‌ای به‌روز باشد. آن‌ها را برای پنج دقیقه کش کنید.

یک بازدیدکننده هزینه کوئری را پرداخت می‌کند و بقیه نتیجه کش‌شده را دریافت می‌کنند.

نکته نهایی: جلوگیری از بازگشت مشکلات (Regressions)

اگر توسعه‌دهندگان بعداً دوباره کد بد را اضافه کنند، پاکسازی‌ها بی‌فایده خواهند بود. از Pest برای تأیید (assert) تعداد کوئری‌های خود استفاده کنید. سقفی برای تعداد کوئری‌هایی که یک صفحه می‌تواند اجرا کند، تعیین کنید. اگر توسعه‌دهنده‌ای یک N+1 اضافه کند، تست با شکست مواجه می‌شود.

بهینه‌سازی عمدتاً درباره حذف کردن است. بارگذاری‌های استفاده نشده را حذف کنید. مقادیر محاسبه مجدد شده را حذف کنید. کوئری‌های غیرضروری را حذف کنید.

Source: https://dev.to/nasrulhazim/a-day-of-performance-hardening-hunting-n1s-and-killing-wasted-queries-in-laravel-568p