تجنب بطء Laravel بسبب whereHas المتداخلة

x32x01
  • بواسطة x32x01 ||
بص يا معلم، لو بتشتغل على Laravel، لازم تاخد بالك من حاجة مهمة جدًا!
فيه ناس بتستخدم دالة whereHas() بطريقة متداخلة جوه بعضها... ودي مصيبة بتضرب أداء التطبيق في الأرض 🚨
عن تجربة شخصية - لو عندك بيانات كتير، الكود ده هيخلّي السيرفر ينهج 😵

يعني إيه whereHas أصلاً؟ 🤔

دالة whereHas() في Laravel Eloquent بتستخدمها لما تحب تجيب البيانات اللي ليها علاقة بشروط معينة من جداول تانية.
يعني مثلًا، لو عندك جدول الاشتراكات (subscriptions) وجواه علاقات مع الخصائص (features) والأسعار (prices)
تقدر تستخدمها عشان تجيب الاشتراكات اللي فيها أسعار معينة أو خصائص محددة.

بس المشكلة مش في الدالة نفسها... المشكلة في التداخل! 👇



💥 مثال على الكارثة​

الكود ده شكله بسيط... لكن هو اللي بيولّع السيرفر 🔥
PHP:
Subscription::whereHas('features', function ($query) {
    $query->whereHas('prices', function ($query) {
        $query->where('amount', '>', 100);
    });
})->get();
اللي بيحصل هنا إن Laravel بيعمل استعلام فرعي (Subquery) لكل سطر تقريبًا!
وده معناه إنك لو عندك آلاف السجلات… هيعمل آلاف الاستعلامات! 😨



💣 ليه الكود ده بيبوّظ الأداء؟​

فيه سببين رئيسيين:

1. تكرار الاستعلامات الفرعية 🔁

كل مرة بيعمل whereHas متداخلة، بيتنفذ استعلام جديد في الخلفية.
وده بيزود الحمل على قاعدة البيانات بشكل كبير جدًا، خصوصًا لو عندك آلاف الصفوف.

2. Full Table Scan 🧾

Laravel بيعمل مسح كامل لجدول الأسعار (prices) عشان يلاقي السجلات المناسبة.
تخيل معايا جدول فيه مليون صف، هيفضل يقرأهم كلهم واحد واحد 😩
وده معناه بطء رهيب جدًا في الأداء.



🧠 الحل؟ استخدم العلاقات بطريقة ذكية!​

Laravel عندها مميزات تخليك توصل لنفس النتيجة بدون وجع دماغ ولا تبطئة.



✅ الطريقة الصحيحة: العلاقات المترابطة​

بدل ما تعمل whereHas جوه whereHas، استخدم العلاقات المترابطة بالشكل ده:
PHP:
Subscription::whereHas('features.prices', function ($query) {
    $query->where('amount', '>', 100);
})->get();

هنا Laravel بيترجم العلاقة بشكل مباشر بدون ما يعمل استعلام متداخل لكل سجل.
النتيجة؟ ⚡ أداء أسرع بكتير وqueries أقل بكتير!



⚙️ طريقة تانية قوية: استخدم with() لتحميل البيانات مسبقًا​

لو هدفك إنك تجيب البيانات كلها بعلاقاتها في استعلام واحد، استخدم with() 👇
PHP:
Subscription::with(['features.prices' => function ($query) {
    $query->where('amount', '>', 100);
}])->get();

الميزة هنا إن Laravel بيستخدم Eager Loading بدل Lazy Loading
وده يعني إنه بيحمّل البيانات كلها في استعلام واحد منظم وفعال 👌



⚡ الفرق بين whereHas و with باختصار​

الخاصيةwhereHaswith
الوظيفةتصفية السجلات بناءً على علاقةتحميل العلاقات مسبقًا
الأداءأبطأ لو متداخلةأسرع ومناسب للبيانات الكبيرة
الاستخداملما تكون عايز فلترة دقيقةلما تكون عايز بيانات كاملة بعلاقاتها

🧩 نصيحة للمطورين​

لو بتتعامل مع Eloquent ORM في Laravel:
  • ✅ استخدم relationships المتسلسلة بدل التداخل المتكرر.
  • ✅ فعّل الـ query logging وشوف الاستعلامات اللي بتتنفذ فعليًا.
  • ✅ جرّب دايمًا تحسّن الكود بالأداء مش بالشكل.

افتكر دايمًا 👇
الكود الحلو مش اللي بيشتغل بس… الكود الحلو هو اللي بيشتغل بسرعة وكفاءة ⚡

💬 خلاصة الكلام​

استخدام whereHas مش غلط، لكن التداخل فيها بيكلفك كتير من ناحية الأداء ⛔
بدلها بالعلاقات المباشرة أو استخدم with() لما تحتاج تحمّل البيانات مسبقًا.
الموضوع بسيط بس فرقه كبير جدًا في السرعة والأداء 🔥
 
التعديل الأخير:
المواضيع ذات الصلة
x32x01
الردود
0
المشاهدات
359
x32x01
x32x01
x32x01
الردود
0
المشاهدات
390
x32x01
x32x01
x32x01
الردود
0
المشاهدات
429
x32x01
x32x01
x32x01
الردود
0
المشاهدات
602
x32x01
x32x01
x32x01
الردود
0
المشاهدات
344
x32x01
x32x01
x32x01
الردود
0
المشاهدات
548
x32x01
x32x01
x32x01
الردود
0
المشاهدات
1K
x32x01
x32x01
x32x01
الردود
0
المشاهدات
333
x32x01
x32x01
x32x01
الردود
0
المشاهدات
398
x32x01
x32x01
x32x01
الردود
0
المشاهدات
385
x32x01
x32x01
الدخول أو التسجيل السريع
نسيت كلمة مرورك؟
إحصائيات المنتدى
المواضيع
1,830
المشاركات
2,027
أعضاء أكتب كود
466
أخر عضو
chaouki
عودة
أعلى