תשובה קצרה: אפליקציה שנבנתה ב-Lovable ונהיית איטית עם משתמשים אמיתיים סובלת כמעט תמיד מאחת משש בעיות, ואפשר לבדוק אותן לפי הסדר: שאילתות שמושכות טבלה שלמה, אינדקס חסר, רשימה בלי עימוד, מדיניות RLS שרצה על כל שורה, חיבורים למסד הנתונים שנגמרים בעומס, ורינדור כבד בדפדפן. מתחילים במסד הנתונים, כי שם נמצאת רוב האיטיות. ברוב המקרים מתקנים את הקוד הקיים ולא בונים מחדש.
למה זה עבד בבדיקות ונשבר עכשיו?
בבדיקות היו בטבלה עשרות שורות ומשתמש אחד. בתנאים האלה כל שאילתה מהירה, גם אם היא כתובה רע. Lovable בונה מסך שעובד, והיא לא יודעת כמה שורות יהיו בטבלה בעוד חצי שנה. שלושה דברים משתנים כשמגיעים משתמשים: הטבלאות גדלות, כמה אנשים פונים למסד הנתונים באותו רגע, ומופיעים מקרים שלא נבדקו (משתמש עם אלף רשומות, שני אנשים שעורכים את אותה שורה).
האיטיות היא בעיה הנדסית רגילה. היא לא אומרת שהכלי נכשל, והיא לא אומרת שצריך לזרוק את מה שנבנה.
איך מוצאים את השאילתות האיטיות?
1. רשימת השאילתות היקרות
לפני שמשנים משהו, מודדים. התיעוד של Supabase מפרט פקודות CLI שקוראות את הסטטיסטיקה של מסד הנתונים.
איך בודקים:
supabase inspect db outliers
supabase inspect db seq-scans
supabase inspect db long-running-queries
הראשונה מציגה את השאילתות שלוקחות הכי הרבה זמן. השנייה מציגה כמה פעמים כל טבלה נסרקה במלואה. השלישית מציגה מה רץ ברגע זה ולא מסתיים.
איך נראה רע: טבלה גדולה עם מספר גבוה של סריקות מלאות, או שאילתה אחת שתופסת את רוב זמן הריצה. זו השאילתה שמתחילים ממנה.
2. אינדקס על העמודות שמסננים לפיהן
אינדקס הוא מה שמאפשר למסד הנתונים למצוא שורות בלי לקרוא את כל הטבלה. Lovable יוצרת טבלאות עם מפתח ראשי, ולא תמיד מוסיפה אינדקס לעמודות כמו user_id, org_id או created_at, שלפיהן כמעט כל מסך מסנן וממיין.
איך בודקים: לכל טבלה שעלתה בבדיקה 1, רשמו לפי אילו עמודות האפליקציה מסננת וממיינת, והריצו:
select indexname, indexdef
from pg_indexes
where schemaname = 'public' and tablename = 'שם_הטבלה';
איך נראה רע: אין אינדקס על עמודה שמופיעה בסינון. באחד הפרויקטים שטיפלנו בהם טבלת לידים של מיליון שורות רצה בלי אינדקסים.
3. עימוד בכל רשימה שגדלה
איך בודקים: פתחו את לשונית Network וטענו כל מסך שמציג רשימה. בדקו כמה שורות חוזרות בבקשה לנתיב /rest/v1/.
איך נראה רע: המסך מציג עשרים שורות והבקשה מחזירה את כל הטבלה. התיקון הוא לבקש רק את העמוד שמוצג (range בספריית הלקוח של Supabase), ולבקש רק את העמודות שהמסך צריך במקום select('*').
למה RLS מאט את האפליקציה, ואיך מתקנים בלי לכבות אותו?
4. מדיניות RLS שרצה על כל שורה
RLS הוא מה שמפריד בין הנתונים של משתמש אחד לאחר, ואסור לכבות אותו כדי להרוויח מהירות. מה שכן אפשר לעשות מפורט במדריך הביצועים של Supabase ל-RLS, ושלושה דברים ממנו פותרים את רוב המקרים:
- אינדקס על העמודות שהמדיניות משתמשת בהן. לפי המדריך, בטבלאות גדולות השיפור עבר פי 100.
- לעטוף את הפונקציה ב-select. במקום
auth.uid() = user_idכותבים(select auth.uid()) = user_id, כך שהפונקציה מחושבת פעם אחת לשאילתה ולא לכל שורה. - לסנן גם בשאילתה עצמה. המדריך אומר במפורש לא להסתמך על RLS לסינון אלא רק לאבטחה. מוסיפים
.eq('user_id', userId)גם כשהמדיניות כבר מגבילה.
איך בודקים: קראו את המדיניות של הטבלאות האיטיות:
select tablename, policyname, qual
from pg_policies
where schemaname = 'public';
איך נראה רע: auth.uid() בלי עטיפה, מדיניות שמריצה תת-שאילתה על טבלה אחרת לכל שורה, או עמודה במדיניות שאין עליה אינדקס. אם אחרי התיקון המדיניות עדיין לא מגינה כמו שצריך, הטעויות הנפוצות מפורטות במדריך ל-RLS שלא עובד ב-Supabase.
מה קורה כשהרבה משתמשים מתחברים באותו רגע?
5. חיבורים למסד הנתונים
לכל מסד נתונים יש מספר מוגבל של חיבורים. Edge Functions פותחות הרבה חיבורים קצרים, ואם כל אחת פותחת חיבור ישיר, הם נגמרים בדיוק ברגע העומס. לפי התיעוד של Supabase, פונקציות serverless ו-edge צריכות להתחבר דרך ה-pooler במצב transaction (פורט 6543), וחיבור ישיר (פורט 5432) מתאים לשרתים שרצים קבוע.
איך בודקים: חפשו בקוד של ה-Edge Functions את מחרוזת החיבור ובדקו לאיזה פורט היא פונה. בדף השימוש בלוח בדקו את מספר החיבורים בשעת העומס.
איך נראה רע: שגיאות על יותר מדי חיבורים בלוגים בשעות העומס, או פונקציה שמתחברת ישירות. באחד הפרויקטים שטיפלנו בהם ה-connection pool הוגבל ל-15 חיבורים והמערכת לא עמדה ביום עומס.
מה אם השרת מהיר והמסך עדיין נתקע?
6. רינדור בצד הלקוח
איך בודקים: בלשונית Network, אם הבקשות חוזרות מהר והמסך עדיין איטי, הבעיה בדפדפן. פתחו את לשונית Performance, הקליטו טעינה של המסך, וחפשו בלשונית Network בקשות זהות שחוזרות על עצמן.
איך נראה רע: רשימה של אלפי שורות שמוצגת בבת אחת, אותה בקשה שנשלחת כמה פעמים בכל טעינה, או רכיב שמבקש נתונים מחדש בכל הקלדה. התיקונים: עימוד או רשימה וירטואלית, שמירת תוצאות בזיכרון (cache) בספריית השאילתות, והשהיה (debounce) על שדות חיפוש.
שש הבדיקות בטבלה אחת
| # | בדיקה | איך בודקים | איך נראה רע |
|---|---|---|---|
| 1 | שאילתות יקרות | supabase inspect db outliers ו-seq-scans | שאילתה אחת שתופסת את רוב הזמן |
| 2 | אינדקסים | pg_indexes מול העמודות שמסננים לפיהן | סינון על עמודה בלי אינדקס |
| 3 | עימוד | מספר השורות שחוזרות ב-Network | כל הטבלה חוזרת למסך של עשרים שורות |
| 4 | RLS איטי | pg_policies | auth.uid() בלי עטיפה, עמודה בלי אינדקס |
| 5 | חיבורים | פורט החיבור ב-Edge Functions | חיבור ישיר, שגיאות חיבורים בעומס |
| 6 | צד הלקוח | Network ו-Performance | בקשות כפולות, רשימה ענקית בבת אחת |
מתי מתקנים ומתי בונים מחדש?
מתקנים כשהבעיות הן מהרשימה למעלה. אינדקס, עימוד, מדיניות RLS וסוג החיבור הם שינויים בקוד הקיים, והמשתמשים לא מרגישים אותם חוץ מזה שהמסך נטען מהר.
שוקלים בנייה מחדש של חלק מהמערכת בשלושה מצבים: מבנה הנתונים לא מחזיק את המוצר (למשל אין הפרדה בין לקוחות עסקיים, וצריך להוסיף אותה לכל טבלה), אין סביבת בדיקה וכל תיקון שובר שני דברים אחרים, או שהאפליקציה מחזיקה תשלומים ומידע אישי ואף אחד לא יודע להגיד מה מוגן.
האפשרויות, מי מבצע כל אחת ומה היא דורשת מפורטות במדריך לתיקון אפליקציית Lovable או Base44. אם עוד לא עליתם לאוויר, עברו קודם על הצ'קליסט לפני השקה. העבודה המלאה של מעבר מ-POC לפרודקשן מפורטת במדריך ההנדסי ל-Lovable בפרודקשן.
מתי כדאי שמהנדס יעבור על זה?
אם הרצתם את שש הבדיקות ומצאתם את הבעיה, תקנו אותה. כדאי להביא מהנדס כשהאיטיות חוזרת אחרי התיקון, כשאין לכם דרך לבדוק שינוי לפני שהוא מגיע ללקוחות, או כשהאפליקציה כבר מכניסה כסף וכל שעת תקלה עולה לכם לקוחות.
בבדיקה לפני השקה מהנדס עובר על האבטחה וההרשאות, מבנה הנתונים והעומס, התשלומים ועלות האירוח, ומוסר דוח בעברית עם תיקונים מדורגים לפי עדיפות וטווח עלות לכל תיקון. היא מתאימה גם לאפליקציה שכבר באוויר.
מקורות
- Supabase Docs - בדיקת מסד הנתונים (inspect db): פקודות inspect db לשאילתות יקרות, סריקות מלאות ושאילתות ארוכות
- Supabase Docs - RLS Performance and Best Practices: אינדקסים על עמודות המדיניות, עטיפת auth.uid() ב-select, סינון בשאילתה
- Supabase Docs - התחברות למסד הנתונים: חיבור ישיר מול pooler, ומצב transaction לפונקציות serverless
האפליקציה איטית ואתם לא בטוחים מאיפה להתחיל? בעמוד הבדיקה לפני השקה אפשר לקבוע שיחת וואטסאפ חינמית של 20 דקות. מספרים מה נשבר ובאיזה מסך, ונגיד לכם אם זה תיקון נקודתי או שצריך בדיקה מלאה.
