ה-SQL שלך מהיר אבל ה-API איטי
שאילתות מסד הנתונים שלך מהירות. המטמון (caching) שלך עובד. תהליכי הרקע (background jobs) שלך תקינים.
ובכל זאת, ה-API שלך עדיין איטי. ניצול ה-CPU שלך גבוה.
הבעיה היא לא מסד הנתונים שלך. הבעיה היא שכבת ה-Ruby.
צוואר הבקבוק מתרחש לעיתים קרובות לאחר שהנתונים עוזבים את מסד הנתונים ונכנסים לאפליקציה שלך. זה קורה בשל שלוש בעיות עיקריות:
- סריאליזציה (serialization) מנופחת
- הקצאת אובייקטים מוגזמת
- חישובים חוזרים ונשנים
הנה איך לתקן אותן.
1. הפסק סריאליזציה מנופחת
מפתחים רבים הופכים מודלים שלמים ל-JSON.
render json: @shipments
אם למשלוח יש 40 עמודות אבל ה-frontend שלך זקוק רק ל-5, אתה מבזבז מחזורי CPU. אתה גם מסתכן בדליפת נתונים פרטיים כמו מפתחות API או עלויות.
הפתרון: החזר רק את השדות שאתה צריך.
render json: @shipments.as_json(only: [:id, :tracking_no, :status])
למהירות טובה עוד יותר, השתמש ב-pluck כדי לשלוף נתונים כמערכים. זה מונע לחלוטין בנייה של אובייקטי ActiveRecord כבדים.
2. צמצם הקצאת אובייקטים
כל אובייקט ש-Ruby יוצר עולה בזיכרון. יצירת אלפי אובייקטים במהלך בקשה בודדת מאלצת את ה-Garbage Collector (GC) לעבוד קשה יותר. זה מאט את המערכת כולה.
הימנע מבניית hashes או מחרוזות חדשות בתוך לולאות.
גרוע:
@shipments.map do |s|
{ label: "#{s.tracking_no} - #{s.status.upcase}" }
end
טוב: העבר נתונים סטטיים מחוץ ללולאה. בצע יותר עבודה במסד הנתונים במקום ב-Ruby.
3. הימנע מחישובים חוזרים ונשנים
אם אתה קורא לאותה מתודה מספר פעמים בבקשה אחת, אתה מבזבז זמן.
דוגמה:
def total_weight
shipments.sum(&:weight)
end
אם ה-view, ה-helper וה-serializer שלך כולם קוראים לזה, אתה מחשב את הסכום שלוש פעמים.
הפתרון: השתמש ב-memoization.
def total_weight
@total_weight ||= shipments.sum(&:weight)
end
זה מבטיח שהחישוב יתבצע רק פעם אחת בכל בקשה.
טבלת סיכום:
- סריאליזציה מנופחת: החזר רק שדות נחוצים או השתמש ב-
pluck. - הקצאה גבוהה: בנה פחות אובייקטים בתוך לולאות.
- חישובים חוזרים ונשנים: השתמש ב-memoization כדי לעשות שימוש חוזר בתוצאות.
אופטימיזציה של מסד הנתונים פירושה לבקש פחות נתונים. אופטימיזציה של האפליקציה פירושה לבצע פחות "עבודת פרך" (busywork) ברגע שיש לך את הנתונים.
מקור: https://dev.to/danewu/your-sql-is-fast-but-the-api-is-slow-its-the-ruby-layer-2fno
