استعلامات SQL لديك سريعة ولكن الـ API بطيء
استعلامات قاعدة البيانات لديك سريعة. التخزين المؤقت (caching) يعمل بشكل جيد. والمهام الخلفية (background jobs) تسير على ما يرام.
ومع ذلك، لا تزال واجهة برمجة التطبيقات (API) بطيئة، واستهلاك المعالج (CPU) مرتفع.
المشكلة ليست في قاعدة البيانات. المشكلة تكمن في طبقة Ruby.
غالبًا ما يحدث عنق الزجاجة (bottleneck) بعد خروج البيانات من قاعدة البيانات ودخولها إلى تطبيقك. ويحدث ذلك من خلال ثلاث مشكلات رئيسية:
- التسلسل المتضخم للبيانات (Bloated serialization)
- تخصيص الكائنات المفرط (Excessive object allocation)
- الحسابات المتكررة (Repeated computation)
إليك كيفية إصلاحها.
- توقف عن التسلسل المتضخم للبيانات (Bloated Serialization)
يقوم العديد من المطورين بتحويل النماذج (models) بالكامل إلى JSON.
render json: @shipments
إذا كانت الشحنة تحتوي على 40 عمودًا بينما يحتاج الواجهة الأمامية (frontend) إلى 5 أعمدة فقط، فأنت تهدر دورات المعالج (CPU cycles). كما أنك تخاطر بتسريب بيانات خاصة مثل مفاتيح API أو التكاليف.
الحل: أرجع الحقول التي تحتاجها فقط.
render json: @shipments.as_json(only: [:id, :tracking_no, :status])
للحصول على سرعة أفضل، استخدم pluck لجلب البيانات كمصفوفات (arrays). هذا يتجنب بناء كائنات ActiveRecord الثقيلة تمامًا.
- تقليل تخصيص الكائنات (Object Allocation)
كل كائن (object) ينشئه Ruby يستهلك ذاكرة. إن إنشاء آلاف الكائنات خلال طلب واحد يجبر جامع المهملات (Garbage Collector - GC) على العمل بجهد أكبر، مما يؤدي إلى إبطاء نظامك بالكامل.
تجنب بناء جداول هاش (hashes) أو سلاسل نصية (strings) جديدة داخل الحلقات التكرارية (loops).
Bad:
@shipments.map do |s|
{ label: "#{s.tracking_no} - #{s.status.upcase}" }
end
Good: انقل البيانات الثابتة خارج الحلقة التكرارية. قم بإجراء المزيد من العمل في قاعدة البيانات بدلاً من Ruby.
- تجنب الحسابات المتكررة (Repeated Computation)
إذا قمت باستدعاء نفس الطريقة (method) عدة مرات في طلب واحد، فأنت تضيع الوقت.
Example:
def total_weight
shipments.sum(&:weight)
end
إذا كانت العرض (view) والمساعد (helper) والمُسلسل (serializer) يستدعون هذا جميعًا، فستقوم بحساب المجموع ثلاث مرات.
الحل: استخدم تقنية الـ memoization.
def total_weight
@total_weight ||= shipments.sum(&:weight)
end
يضمن ذلك إجراء العملية الحسابية مرة واحدة فقط لكل طلب.
جدول ملخص:
- التسلسل المتضخم للبيانات: أرجع الحقول المطلوبة فقط أو استخدم
pluck. - التخصيص المرتفع: قم ببناء كائنات أقل داخل الحلقات التكرارية.
- الحسابات المتكررة: استخدم الـ memoization لإعادة استخدام النتائج.
تحسين قاعدة البيانات يعني طلب بيانات أقل. أما تحسين التطبيق فيعني القيام بعمليات ثانوية أقل بمجرد حصولك على البيانات.
Source: https://dev.to/danewu/your-sql-is-fast-but-the-api-is-slow-its-the-ruby-layer-2fno
