एक Magento डेवलपर ने 300 अलग-अलग ProductRepositoryInterface::getById() कॉल्स को एक सिंगल कलेक्शन क्वेरी (collection query) से बदल दिया। डेटाबेस हिट्स 300 से घटकर 1 रह गए, और कैटेगरी पेज काफी तेजी से लोड होने लगा। लेकिन इसका नुकसान क्या हुआ? स्टोरफ्रंट से कुछ प्रोडक्ट्स गायब हो गए, जिससे ग्राहक और मालिक दोनों हैरान रह गए।

Magento कैटेगरी पेज पर N+1 समस्या

पेज पर 300 प्रोडक्ट्स लिस्टेड थे। प्रत्येक प्रोडक्ट के लिए, कोड ने रिपॉजिटरी के getById() मेथड के माध्यम से दो कस्टम एट्रिब्यूट्स (custom attributes) फेच किए, जिससे प्रति प्रोडक्ट एक क्वेरी जनरेट हुई—यही क्लासिक N+1 पैटर्न है। उन प्रति-प्रोडक्ट लोड्स को एक कलेक्शन से बदलने से, जो एक ही क्वेरी में सभी आवश्यक रोज़ (rows) को खींच लेता है, क्वेरी काउंट में भारी कमी आई। फ्रंट-एंड लेटेंसी (latency) में सुधार हुआ, लेकिन अब प्रोडक्ट लिस्ट में वे आइटम गायब थे जो पहले दिखाई देते थे।

कलेक्शन आउट-ऑफ-स्टॉक (out-of-stock) आइटम्स को क्यों छुपा देता है

Magento का CatalogInventory मॉड्यूल फ्रंटएंड के लिए बनाए गए किसी भी प्रोडक्ट कलेक्शन में स्वचालित रूप से एक "in-stock" फ़िल्टर जोड़ देता है। यह फ़िल्टर तब सक्रिय होता है जब स्टोर सेटिंग Display Out of Stock Products को बंद कर दिया जाता है, जो उन व्यापारियों के लिए एक सामान्य विकल्प है जो अनुपलब्ध आइटम नहीं दिखाना चाहते।

इसके विपरीत, रिपॉजिटरी कभी भी स्टॉक फ़िल्टर लागू नहीं करती है। यह केवल यह जाँचती है कि प्रोडक्ट मौजूद है या नहीं और इन्वेंट्री लेवल की परवाह किए बिना उसे वापस कर देती है। जब कोड रिपॉजिटरी कॉल्स से बदलकर कलेक्शन पर आया, तो स्टॉक फ़िल्टर ने चुपचाप उन सभी प्रोडक्ट्स को हटा दिया जिनकी मात्रा (quantity) शून्य थी। कोई एरर लॉग नहीं हुआ; कलेक्शन ने बस डेवलपर की अपेक्षा से कम रोज़ वापस किए।

व्यापारियों के लिए इसका क्या अर्थ है

एक स्टोरफ्रंट जो चुपचाप आउट-ऑफ-स्टॉक SKUs को हटा देता है, कई समस्याएं पैदा करता है:

  • फ्रंट-एंड कंपोनेंट्स को मिसिंग एंट्रीज़ मिलती हैं, जिससे खाली लेबल या गलत कीमतें दिखाई देती हैं।
  • डिबगिंग (debugging) कठिन हो जाती है क्योंकि लक्षण—प्रोडक्ट्स का गायब होना—कोई चेतावनी (warning) जनरेट नहीं करता है।

चूंकि अधिकांश ऑटोमेटेड टेस्ट इन-स्टॉक फिक्स्चर (in-stock fixtures) का उपयोग करते हैं, इसलिए यह बग अक्सर तब तक छिपा रहता है जब तक कि साइट वास्तविक इन्वेंट्री के साथ नहीं चलती।

इन्वेंट्री छुपाए बिना स्पीड कैसे बनाए रखें

  1. डिफ़ॉल्ट स्टॉक फ़िल्टर को छोड़ दें – यदि आपको उपलब्धता की परवाह किए बिना प्रत्येक प्रोडक्ट की आवश्यकता है, तो कलेक्शन से फ़िल्टर को स्पष्ट रूप से हटा दें। Magento प्रत्येक क्वेरी के लिए स्टॉक प्लगइन को अक्षम करने या बदलने के तरीके प्रदान करता है।
  2. जब सटीकता महत्वपूर्ण हो तो रिपॉजिटरी का उपयोग करें – रिपॉजिटरी यह गारंटी देती है कि अनुरोधित प्रत्येक प्रोडक्ट ID वापस की जाए, भले ही वह आउट-ऑफ-स्टॉक हो। अतिरिक्त क्वेरीज़ को नियंत्रित करने के लिए परिणामों को कैश (cache) करें या केवल उन्हीं ID को लोड करें जिनकी आपको आवश्यकता है।
  3. रिसोर्स मॉडल या रॉ SQL (raw SQL) का उपयोग करें – आवश्यक एट्रिब्यूट्स के लिए सीधे प्रोडक्ट टेबल को क्वेरी करें। यह सभी कलेक्शन प्लगइन्स को बायपास कर देता है और आपको इस बात पर पूर्ण नियंत्रण देता है कि कौन सी रोज़ शामिल की जानी चाहिए।

स्पीड बनाम सटीकता

एक शोर भरे (noisy) N+1 लूप को सिंगल कलेक्शन क्वेरी से बदलना स्वाभाविक लगता है; लेटेंसी में गिरावट स्पष्ट रूप से महसूस की जा सकती है। फिर भी, एक तेज़ क्वेरी जो गलत प्रोडक्ट्स का सेट वापस करती है, वह एक दोष (defect) है, ऑप्टिमाइज़ेशन नहीं। डेवलपर्स को कच्चे स्पीड (raw speed) और अधूरे कैटलॉग दिखाने के जोखिम के बीच संतुलन बनाना चाहिए।

आगे क्या ध्यान रखें

  • कॉन्फ़िगरेशन ड्रिफ्ट (Configuration drift) – सत्यापित करें कि Display Out of Stock Products फ्लैग किसी भी कस्टम कलेक्शन कोड के इच्छित व्यवहार से मेल खाता है।
  • प्लगइन साइड इफेक्ट्स (Plugin side effects) – अन्य मॉड्यूल कलेक्शन में अपने स्वयं के फ़िल्टर जोड़ सकते हैं। जब भी आप क्वेरी रणनीतियों को बदलते हैं, तो प्लगइन स्टैक की समीक्षा करें।

सबक स्पष्ट है: कलेक्शन के साथ N+1 समस्या को ठीक करना तभी सफल होता है जब आप कलेक्शन के डिफ़ॉल्ट फ़िल्टर का भी ऑडिट करें। Magento के इन-बिल्ट स्टॉक फ़िल्टर को अनदेखा करने से आपका कैटलॉग चुपचाप कम हो सकता है, जिससे प्रदर्शन में सुधार राजस्व की हानि में बदल सकता है।