מפתח Magento החליף 300 קריאות נפרדות של ProductRepositoryInterface::getById() בשאילתת collection אחת. מספר הפניות לבסיס הנתונים ירד מ-300 ל-1, ודף הקטגוריה נטען מהר יותר באופן ניכר. המחיר? חלק מהמוצרים נעלמו מחנות המקוונת, מה שבלבל את הקונים ואת בעלי העסק.
בעיית ה-N+1 בדף קטגוריה של Magento
הדף הציג 300 מוצרים. עבור כל אחד מהם, הקוד שלף שני מאפיינים (attributes) מותאמים אישית באמצעות מתודת ה-getById() של ה-repository, מה שיצר שאילתה אחת לכל מוצר — תבנית ה-N+1 הקלאסית. החלפת הטעינות הללו (המתבצעות לכל מוצר בנפרד) ב-collection ששולף את כל השורות הנדרשות בשאילתה אחת צמצמה משמעותית את מספר השאילתות. השיהוי (latency) בצד הלקוח השתפר, אך רשימת המוצרים החסירה כעת פריטים שהופיעו בעבר.
מדוע ה-collection מסתיר פריטים שאינם במלאי
מודול ה-CatalogInventory של Magento מוסיף באופן אוטומטי מסנן "במלאי" (in-stock) לכל product collection שנבנה עבור ה-frontend. המסנן מופעל כאשר הגדרת החנות Display Out of Stock Products כבויה, בחירה נפוצה אצל סוחרים שאינם רוצים להציג פריטים שאינם זמינים.
לעומת זאת, ה-repository לעולם אינו מחיל מסנן מלאי. הוא פשוט בודק שמוצר קיים ומחזיר אותו, ללא קשר לרמת המלאי. כאשר הקוד עבר מקריאות repository ל-collection, מסנן המלאי הסיר בשקט כל מוצר שכמותו הייתה אפס. לא נרשמה שגיאה; ה-collection פשוט החזיר פחות שורות ממה שהמפתח ציפה.
מה המשמעות של זה עבור סוחרים
חנות מקוונת שמסירה בשקט מק"טים (SKUs) שאינם במלאי יוצרת מספר בעיות:
- רכיבי ה-front-end מקבלים נתונים חסרים, מה שיוצר תוויות ריקות או תמחור שגוי.
- ניפוי שגיאות (debugging) הופך לקשה יותר מכיוון שהסימפטום — מוצרים חסרים — אינו מייצר אזהרות.
מכיוון שרוב הבדיקות האוטומטיות משתמשות בנתוני בדיקה (fixtures) של מוצרים במלאי, הבאג נשאר לרוב חבוי עד שהאתר פועל עם מלאי אמיתי.
איך לשמור על מהירות מבלי להסתיר מלאי
- דלגו על מסנן המלאי ברירת המחדל – הסירו במפורש את המסנן מה-collection אם אתם זקוקים לכל מוצר ללא קשר לזמינותו. Magento מציעה שיטות לביטול או החלפה של ה-stock plugin עבור שאילתה ספציפית.
- השתמשו ב-repository כשדיוק הוא קריטי – ה-repository מבטיח שכל מזהה מוצר (ID) שהתבקש יוחזר, גם אם הוא אינו במלאי. שמרו את התוצאות בזיכרון מטמון (cache) או טענו רק את ה-IDs הדרושים לכם כדי לצמצם את כמות השאילתות הנוספות.
- השתמשו ב-resource model או ב-SQL גולמי (raw SQL) – בצעו שאילתה ישירות על טבלת המוצרים עבור המאפיינים הנדרשים. פעולה זו עוקפת את כל ה-collection plugins ומעניקה לכם שליטה מלאה על השורות שייכללו.
מהירות מול נכונות
החלפת לולאת N+1 "רועשת" בשאילתת collection אחת מרגישה טבעית; הירידה בשיהוי היא מוחשית. עם זאת, שאילתה מהירה יותר שמחזירה סט מוצרים שגוי היא פגם (defect), ולא אופטימיזציה. מפתחים חייבים לשקול את המהירות הגולמית מול הסיכון של הצגת קטלוג חלקי.
מה כדאי לשים לב אליו בהמשך
- סטייה בהגדרות (Configuration drift) – ודאו שהדגל Display Out of Stock Products תואם להתנהגות המיועדת של כל קוד collection מותאם אישית.
- תופעות לוואי של פלאגינים (Plugin side effects) – מודולים אחרים עשויים להוסיף מסננים משלהם ל-collections. סקרו את מחסנית הפלאגינים (plugin stack) בכל פעם שאתם משנים אסטרטגיות שאילתה.
הלקח ברור: פתרון בעיית N+1 באמצעות collection מועיל רק אם מבצעים גם ביקורת (audit) על מסנני ברירת המחדל של ה-collection. התעלמות ממסנן המלאי המובנה של Magento עלולה לצמצם בשקט את הקטלוג שלכם, ולהפוך שיפור בביצועים להפסד בהכנסות.
