وقتی یک پروژه کند میشود، اولین پیشنهادها معمولاً ارتقای سرور یا اضافهکردن Redis هستند. گاهی مفیدند، اما بدون اندازهگیری فقط مسئله را عقب میاندازند. برای رفع کندی Laravel باید بدانیم زمان دقیقاً کجا مصرف میشود: PHP، دیتابیس، شبکه، serialization یا یک API بیرونی.
یک درخواست واقعی را اندازه بگیرید
از endpoint یا صفحهای شروع کنید که کاربر واقعاً کندی آن را حس میکند. زمان کل، تعداد query، کندترین query، حافظه و تماسهای بیرونی را ثبت کنید. داده production را بدون اطلاعات حساس نمونهبرداری کنید؛ رفتار دیتابیس با هزار رکورد با ده میلیون رکورد یکسان نیست.
Laravel Telescope برای محیط کنترلشده، profiler و slow query log دیتابیس دید خوبی میدهند. هدف جمعکردن ابزار نیست؛ ساختن یک baseline است تا بعد از تغییر بدانیم واقعاً بهتر شدهایم.
N+1 را در رابطهها پیدا کنید
نمایش ۵۰ سفارش و خواندن کاربر هر سفارش میتواند ۵۱ query بسازد. eager loading مشکل را حل میکند، به شرط اینکه فقط ستون و رابطه لازم را بگیریم:
$orders = Order::query()
->with(['customer:id,name'])
->select(['id', 'customer_id', 'total', 'status'])
->latest()
->paginate(30);
در محیط توسعه میتوانید lazy loading ناخواسته را ممنوع کنید تا مشکل پیش از production دیده شود. البته eager load کردن همه رابطهها هم راهحل نیست؛ payload و حافظه میتواند به گلوگاه بعدی تبدیل شود.
EXPLAIN را به حدس ترجیح دهید
برای query کند، SQL واقعی را با bindingها بردارید و EXPLAIN را بررسی کنید. تعداد ردیف تخمینی، نوع دسترسی و index انتخابشده مهماند. index مرکب باید با ترتیب شرطها و sort هماهنگ باشد. دو index جدا روی status و created_at لزوماً جای (status, created_at) را نمیگیرند.
استفاده از function روی ستون، تبدیل نوع و LIKE "%term" میتواند index را بیاثر کند. قبل از اضافهکردن index جدید، indexهای تکراری و هزینه write را هم ببینید.
کمتر بخوانید و کمتر تبدیل کنید
- بهجای
get()نامحدود از pagination یا chunk استفاده کنید. - فقط ستونهای لازم را select کنید.
- برای وجود رکورد از
exists()بهجای دریافت model استفاده کنید. - محاسبه aggregate را در SQL انجام دهید، نه با collection بزرگ PHP.
- responseهای API را از رابطهها و accessorهای گران پاک کنید.
کار سنگین را از مسیر پاسخ خارج کنید
ساخت فایل Excel، ارسال اعلان و پردازش تصویر لازم نیست کاربر را منتظر نگه دارد. Queue تجربه کاربری را بهتر میکند، ولی job باید timeout، retry و idempotency روشن داشته باشد. اگر یک گزارش چند دقیقهای دیتابیس اصلی را قفل میکند، انتقال به صف بهتنهایی فشار را کم نمیکند؛ query و زمان اجرای آن هم باید اصلاح شوند.
کش را هدفمند اضافه کنید
بعد از اصلاح query، داده پرخوانش و کمتغییر کاندید کش است. زمان پاسخ قبل و بعد، hit rate و فشار دیتابیس را بسنجید. کلید باید version و context مثل tenant یا زبان را در نظر بگیرد. برای داده حساس به تازگی، event تغییر میتواند cache را حذف کند.
در راهنمای Redis در Laravel درباره TTL، lock و cache stampede بیشتر توضیح دادهام.
بهینهسازی را با عدد تمام کنید
پس از هر تغییر همان سناریو را با داده مشابه اجرا کنید. میانگین بهتنهایی کافی نیست؛ p95 یا p99 نشان میدهد کاربران کندتر چه تجربهای دارند. مصرف CPU، حافظه، تعداد query و خطا را هم مقایسه کنید تا بهبود یک بخش هزینه را به جای دیگری منتقل نکرده باشد.
اگر قبل و بعد عددی نداریم، بهینهسازی بیشتر یک احساس است تا نتیجه فنی.
برای پروژهای که چند گلوگاه همزمان دارد، ممیزی فنی و کارایی Laravel میتواند گزارش اولویتبندیشده و برنامه اصلاح بسازد.
پرسشهای متداول
چرا پروژه Laravel بعد از افزایش داده کند میشود؟
اغلب queryهایی که روی داده کم بیضرر بودند، بدون index یا با بارگذاری رابطههای اضافی روی حجم واقعی پرهزینه میشوند.
آیا Redis همه مشکلات سرعت را حل میکند؟
نه. کش میتواند فشار را کم کند، اما query بد، payload بزرگ یا طراحی اشتباه را پنهان میکند و مسئله invalidation تازهای میسازد.