प्रतिनिधि इंटरव्यू विषय

बैकएंड इंटरव्यू: आप N+1 क्वेरी समस्या का डायग्नोसिस और समाधान कैसे करते हैं?

बैकएंडकठिन
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

एक ऑर्डर-लिस्ट एंडपॉइंट 50 ऑर्डर फ़ेच करता है और फिर रिस्पॉन्स को सीरियलाइज़ करते समय प्रत्येक ऑर्डर के कस्टमर को पढ़ता है, जिससे 51 SQL स्टेटमेंट बनते हैं। प्रत्येक स्टेटमेंट तेज़ है, लेकिन रिक्वेस्ट लेटेंसी पेज आकार के साथ बढ़ती है। आप N+1 कारण को कैसे साबित करेंगे, समाधान कैसे चुनेंगे और इसे दोबारा होने से कैसे रोकेंगे?

समस्या और प्रासंगिक संदर्भ

एक ऑर्डर-लिस्ट एंडपॉइंट पहले 50 ऑर्डर्स का एक पेज फ़ेच करता है। रिस्पॉन्स सीरियलाइज़ेशन के दौरान, ORM प्रत्येक ऑर्डर के लिए order.customer को अलग से लोड करता है। प्रोडक्शन ट्रेस में एक ऑर्डर क्वेरी और 50 कस्टमर क्वेरीज़ शामिल होती हैं। कोई भी व्यक्तिगत स्टेटमेंट धीमा नहीं दिखता, फिर भी एक रिक्वेस्ट 51 डेटाबेस राउंडट्रिप करती है। जब पेज का आकार दोगुना हो जाता है, तो स्टेटमेंट की संख्या और रिक्वेस्ट लेटेंसी भी उसी के साथ बढ़ जाती है।

मान लें कि प्रत्येक ऑर्डर एक कस्टमर का है, रिस्पॉन्स को केवल कस्टमर के डिस्प्ले नाम की आवश्यकता है, और एंडपॉइंट को अपने वर्तमान क्रम, ऑथराइज़ेशन फ़िल्टर और पेजिनेशन सेमेंटिक्स को बनाए रखना होगा। ये संख्याएं इंटरव्यू के अनुमान हैं जो डायग्नोसिस को परीक्षण योग्य बनाते हैं। मुख्य प्रश्न यह है कि एप्लिकेशन एक्सेस-पैटर्न की समस्या का पता कैसे लगाया जाए, न कि किसी एक धीमी SQL योजना को कैसे ट्यून किया जाए।

लक्षित भूमिका एक रिलेशनल डेटाबेस और ORM के साथ काम करने वाले बैकएंड इंजीनियर की है। एक पूर्ण उत्तर में सिंगल जॉइन्ड क्वेरी, दो-क्वेरी वाले select-in बैच और लोडिंग डिफॉल्ट्स में बदलाव की तुलना होनी चाहिए। इसमें वन-टू-मेनी रिलेशनशिप्स, ट्रांजेक्शन कंसिस्टेंसी, ऑब्जर्वेबिलिटी और एक ऐसा रिग्रेशन चेक भी शामिल होना चाहिए जिसकी क्वेरी संख्या समय (timing) पर निर्भर न हो।

इंटरव्यूअर क्या मूल्यांकन कर रहा है

पहला संकेत यह है कि क्या उम्मीदवार रिक्वेस्ट बाउंड्री पर कार्यभार मापता है। N+1 समस्या में कई व्यक्तिगत रूप से कुशल इंडेक्स की गई क्वेरीज़ हो सकती हैं। केवल स्लो-क्वेरी लॉग को देखना या किसी एक कस्टमर लुकअप पर EXPLAIN चलाना इस मल्टीप्लायर को अनदेखा कर सकता है। उपयोगी साक्ष्य एक ट्रेस या क्वेरी लॉग है जो स्टेटमेंट्स को रिक्वेस्ट के आधार पर समूहित करता है और एक ही कॉल साइट से दोहराए गए समान नॉर्मलाइज़्ड लुकअप को दिखाता है।

दूसरा संकेत एक सही ग्रोथ मॉडल है। N पैरेंट पंक्तियों के लिए, सामान्य (naive) पथ एक पैरेंट क्वेरी और प्रति पैरेंट एक संबंधित-पंक्ति क्वेरी निष्पादित करता है:

text
Q(N) = 1 + N
Q(50) = 51

एक select-in बैच आम तौर पर इसे एक पैरेंट क्वेरी और एक संबंधित-पंक्ति क्वेरी में बदल देता है, इसलिए परीक्षण किए गए पेज आकारों के लिए संख्या दो बनी रहती है। यदि ID सूची को B बैचों में विभाजित किया जाना चाहिए, तो संख्या 1 + B हो जाती है; यह अभी भी प्रति पैरेंट एक बार नहीं बढ़ती है।

तीसरा संकेत रिलेशनशिप कार्डिनैलिटी और रिस्पॉन्स की आवश्यकताओं से लोडिंग का आकार चुनना है। कुछ संकीर्ण कॉलमों वाला मैनी-टू-वन कस्टमर लुकअप अक्सर JOIN के लिए उपयुक्त होता है। एक बड़ा वन-टू-मेनी कलेक्शन परिणाम पंक्तियों को कई गुना बढ़ा सकता है और पैरेंट कॉलम को डुप्लिकेट कर सकता है, जिससे पैरेंट-पेज क्वेरी के बाद बैच चाइल्ड क्वेरी अधिक सुरक्षित हो जाती है। "हर जगह ईगर लोडिंग सक्षम करें" कोई डिज़ाइन नहीं है; कुछ ORM अभी भी ईगर एसोसिएशन के लिए सेकेंडरी सेलेक्ट्स जारी कर सकते हैं, और ग्लोबल ईगर लोडिंग वह डेटा फ़ेच कर सकती है जिसे यह एंडपॉइंट कभी वापस नहीं करता है।

अंत में, इंटरव्यूअर को इस बात के प्रमाण की अपेक्षा होती है कि व्यवहार सुरक्षित रखा गया है। क्वेरी-संख्या में सुधार छूटे हुए टेनेंट फ़िल्टर, बदले हुए पेज सीमाओं, अस्थिर क्रम, असंगत रीड्स या जॉइन के कारण होने वाली अतिरिक्त पंक्तियों को सही नहीं ठहराता है। एक मजबूत उत्तर डेटाबेस कार्य और रिस्पॉन्स समतुल्यता दोनों को मान्य करता है।

उत्तर देने से पहले स्पष्ट करने वाले प्रश्न

  • रिलेशनशिप एक्सेस कहाँ होता है? यदि सीरियलाइज़ेशन, टेम्पलेट, लॉगिंग या मैपर रिपॉजिटरी के लौटने के बाद प्रॉपर्टी को छूता है, तो क्वेरी स्रोत स्पष्ट लूप के बाहर होता है। समाधान को वास्तविक एक्सेस पथ को कवर करना होगा।
  • रिलेशनशिप कार्डिनैलिटी क्या है? मैनी-टू-वन डेटा एक ऑर्डर को कई पंक्तियों में गुणा किए बिना जुड़ सकता है। एक वन-टू-मेनी चाइल्ड कलेक्शन पेजिनेशन और पेलोड-आकार के जोखिम को बदल देता है।
  • किन संबंधित फ़ील्ड्स की आवश्यकता है? एक डिस्प्ले नाम संकीर्ण प्रोजेक्शन का समर्थन करता है। पूरी कस्टमर एंटिटी और प्रत्येक एसोसिएशन को लोड करने से ओवरफेचिंग होती है, भले ही क्वेरी संख्या कम हो जाए।
  • क्या संबंधित IDs दोहराई जाती हैं? रिक्वेस्ट-स्कोप्ड आइडेंटिटी मैप डुप्लिकेट लुकअप को कम कर सकता है, लेकिन जब अधिकांश ID अद्वितीय होती हैं तो यह संख्या को सीमित नहीं करता है। यह मानने के बजाय कि कैश इसे ठीक कर देगा, मापें।
  • पेजिनेशन कैसे लागू किया जाता है? वन-टू-मेनी जॉइन या चाइल्ड लोड से पहले पैरेंट पंक्तियों को एक नियतात्मक क्रम के साथ चुना जाना चाहिए; अन्यथा पंक्ति गुणन बदल सकता है कि कौन से पैरेंट दिखाई देते हैं।
  • क्या दोनों रीड्स को एक स्नैपशॉट साझा करना चाहिए? JOIN एक सिंगल स्टेटमेंट है। पैरेंट क्वेरी के बाद चाइल्ड क्वेरी डिफ़ॉल्ट आइसोलेशन व्यवहार के तहत समवर्ती परिवर्तन देख सकती है। यदि पॉइंट-इन-टाइम कंसिस्टेंसी मायने रखती है, तो उचित ट्रांजेक्शन स्नैपशॉट या सिंगल-स्टेटमेंट आकार का उपयोग करें।
  • ORM वास्तव में क्या जनरेट करता है? eager, include, prefetch, या split query जैसे नाम किसी विशेष स्टेटमेंट संख्या की गारंटी नहीं देते हैं। डिप्लॉय किए गए वर्शन के लिए उत्सर्जित SQL का निरीक्षण करें।

30-सेकंड उत्तर रूपरेखा

"मैं डेटाबेस स्पैन को रिक्वेस्ट के अनुसार समूहित करूँगा और एक पेज क्वेरी के बाद 50 बार समान नॉर्मलाइज़्ड कस्टमर लुकअप को सत्यापित करूँगा। फिर मैं पेज का आकार बदलूँगा; 10, 20 और 40 के पेजों के लिए 11, 21 और 41 की संख्या रैखिक क्वेरी प्रवर्धन साबित करती है, भले ही प्रत्येक लुकअप तेज़ हो। इस मैनी-टू-वन डिस्प्ले-नेम फ़ील्ड के लिए, मैं एक संकीर्ण JOIN की तुलना दो-क्वेरी select-in बैच से करूँगा। मैं ग्लोबल ईगर डिफ़ॉल्ट से बचूँगा क्योंकि यह ओवरफेच कर सकता है और एक स्टेटमेंट की गारंटी नहीं देता है। एक बड़े वन-टू-मेनी संबंध के लिए, मैं पंक्ति गुणन से बचने के लिए पहले पैरेंट्स को पेज करूँगा और बच्चों को बैच करूँगा। अंत में, मैं एक स्थिर क्वेरी बजट का दावा करूँगा, रिस्पॉन्स IDs और क्रम की तुलना करूँगा, और रोलआउट के बाद रिक्वेस्ट-स्तरीय क्वेरी संख्या और लेटेंसी की निगरानी करूँगा।"

चरण-दर-चरण गहन विश्लेषण

चरण 1: रिक्वेस्ट बाउंड्री पर प्रवर्धन साबित करें

डेटाबेस स्पैन में एक रिक्वेस्ट या ट्रेस ID संलग्न करें, पैरामीटर मानों को बदलकर SQL को नॉर्मलाइज़ करें, और कॉल साइट द्वारा समूहित करें। संदिग्ध ट्रेस संरचनात्मक रूप से इस तरह दिखना चाहिए:

text
1 × SELECT id, customer_id, created_at, total_cents FROM orders ... LIMIT ?
50 × SELECT id, display_name FROM customers WHERE id = ?

दोहराया गया फ़िंगरप्रिंट और रैखिक स्केलिंग N+1 को एक महंगे स्टेटमेंट, लॉक वेट, कनेक्शन-पूल कतार या धीमे सीरियलाइज़र से अलग करता है। स्टेटमेंट की अवधि के साथ-साथ कुल डेटाबेस अवधि और राउंडट्रिप संख्या रिकॉर्ड करें। पचास 1-मिलीसेकंड की क्वेरीज़ एक 51-मिलीसेकंड की क्वेरी के बराबर नहीं होती हैं क्योंकि प्रत्येक राउंडट्रिप कनेक्शन, प्रोटोकॉल कार्य और शेड्यूलर समय की भी खपत करती है।

10, 20 और 40 के नियंत्रित पेज आकारों के साथ रिक्वेस्ट दोहराएं। 11, 21 और 41 की संख्या एक मजबूत कारण हस्ताक्षर है। रिलेशनशिप फ़ील्ड को अस्थायी रूप से हटाने से अतिरिक्त क्वेरीज़ समाप्त हो जानी चाहिए; यह पुष्टि करता है कि कौन सा प्रॉपर्टी एक्सेस लोडिंग को ट्रिगर करता है। यह प्रयोग पहले से इंडेक्स किए गए प्राइमरी-की लुकअप में इंडेक्स जोड़ने की तुलना में अधिक उपयोगी है।

चरण 2: लोडिंग बदलने से पहले आवश्यक परिणाम परिभाषित करें

रिस्पॉन्स अनुबंध लिखें: क्रमित ऑर्डर IDs, कर्सर या पेज सीमा, अनुमत टेनेंट और सटीक कस्टमर फ़ील्ड। यह भी तय करें कि अनुपलब्ध या हटाए गए कस्टमर कैसे दिखाई देते हैं। यह क्वेरी ऑप्टिमाइज़ेशन को चुपचाप डेटा-अनुबंध परिवर्तन बनने से रोकता है।

बैच किए गए पथ में ऑथराइज़ेशन और सॉफ्ट-डिलीट प्रेडिकेट्स बनाए रखें। यदि मूल रिलेशनशिप लोडर ने टेनेंट स्कोप लागू किया था, तो हाथ से लिखी गई WHERE id = ANY(...) क्वेरी जो टेनेंट स्कोप को छोड़ देती है, डेटा लीक बन सकती है। क्वेरी संख्या केवल एक स्वीकृति मानदंड है।

चरण 3: संकीर्ण JOIN और select-in बैच के बीच चयन करें

अनिवार्य मैनी-टू-वन संबंध और संकीर्ण रिस्पॉन्स के लिए, एकल जॉइन्ड स्टेटमेंट सरल है:

sql
SELECT
  o.id,
  o.created_at,
  o.total_cents,
  c.id AS customer_id,
  c.display_name
FROM orders AS o
JOIN customers AS c
  ON c.id = o.customer_id
 AND c.tenant_id = o.tenant_id
WHERE o.tenant_id = $1
ORDER BY o.created_at DESC, o.id DESC
LIMIT $2;

o.id पर टाई-ब्रेकर क्रम को नियतात्मक बनाता है। इसके बजाय लेफ्ट जॉइन का उपयोग करें यदि कोई ऑर्डर वैध रूप से अपने कस्टमर रिकॉर्ड से अधिक समय तक बना रह सकता है और मौजूदा अनुबंध उस ऑर्डर को लौटाता है।

दो-क्वेरी बैच पैरेंट पेजिनेशन को अलग रखता है और तब अच्छा काम करता है जब जॉइन की चौड़ाई या कलेक्शन कार्डिनैलिटी परिणाम को फुला देती है। निम्नलिखित उदाहरणात्मक TypeScript IDs को डिडुप्लिकेट करता है, केवल आवश्यक कॉलम लोड करता है, और उन्हें मेमोरी में मैप करता है:

ts
interface OrderRow {
  id: string
  customerId: string
  createdAt: Date
  totalCents: number
}

interface CustomerRow {
  id: string
  displayName: string
}

const orders = await loadOrderPage(tenantId, limit)
const customerIds = [...new Set(orders.map((order) => order.customerId))]
const customers = await loadCustomersByIds(tenantId, customerIds)
const customerById = new Map(customers.map((customer) => [customer.id, customer]))

return orders.map((order) => ({
  ...order,
  customer: customerById.get(order.customerId) ?? null,
}))

रिपॉजिटरी के loadCustomersByIds को एक सामान्य पेज के लिए एक सेट-आधारित प्रेडिकेट का उपयोग करना चाहिए और असामान्य रूप से बड़ी ID सूचियों को सीमित बैचों में विभाजित करना चाहिए। डिडुप्लिकेशन स्थानांतरित पैरामीटर को कम करता है; यह मुख्य समाधान नहीं है। मुख्य समाधान संबंधित लोड को प्रति-पंक्ति एक्सेस पथ से बाहर ले जाना है।

चरण 4: पेजिनेशन को तोड़े बिना वन-टू-मेनी संबंधों को संभालें

मान लीजिए कि प्रत्येक ऑर्डर कई लाइन आइटम भी लौटाता है। ऑर्डर्स, कस्टमर्स और आइटम्स को जोड़ने से प्रति आइटम एक पंक्ति उत्सर्जित हो सकती है और ऑर्डर कॉलम दोहराए जा सकते हैं। उस जॉइन के बाद LIMIT 50 लागू करने से जॉइन्ड पंक्तियाँ सीमित हो सकती हैं, न कि 50 अलग-अलग ऑर्डर। एक जॉइन में कई कलेक्शन्स लोड करने से वे एक-दूसरे के विरुद्ध कई गुना बढ़ सकते हैं।

पहले एक स्थिर क्रम के साथ 50 पैरेंट ऑर्डर्स का चयन करें, फिर उन सभी आइटम्स को फ़ेच करें जिनका order_id उस पैरेंट ID सेट में है। आइटम्स को order_id द्वारा समूहित करें और उन्हें मूल पैरेंट क्रम में संलग्न करें। यही व्यावहारिक कारण है कि आधिकारिक ORM दस्तावेज़ एक सार्वभौमिक ईगर-लोडिंग स्विच के बजाय joined, subquery, select-in, और split-query रणनीतियाँ प्रदान करते हैं।

चरण 5: शॉर्टकट के रूप में ग्लोबल लोडिंग परिवर्तनों को अस्वीकार करें

प्रत्येक संबंध को लेज़ी से ईगर में बदलना समस्या को हल करने के बजाय स्थानांतरित कर सकता है। जिन एंडपॉइंट्स को कस्टमर्स की आवश्यकता नहीं है, वे अब उन्हें ओवरफ़ेच करते हैं। एक क्वेरी जो किसी ईगर एसोसिएशन को जॉइन-फ़ेच नहीं करती है, वह अभी भी कुछ ORM व्यवहार में सेकेंडरी सेलेक्ट्स को भड़का सकती है। विस्तृत ऑब्जेक्ट ग्राफ़ बड़े जॉइन या चक्र भी बना सकते हैं जिनका अनुमान लगाना कठिन होता है।

एंडपॉइंट-विशिष्ट प्रोजेक्शन या स्पष्ट लोडिंग योजना को प्राथमिकता दें। विकास और परीक्षणों में, उपलब्ध होने पर एक ORM विकल्प का उपयोग करें जो अप्रत्याशित लेज़ी SQL पर अपवाद उत्पन्न करता है। यह छिपे हुए डेटाबेस एक्सेस को उस सीमा पर एक दृश्य विफलता में बदल देता है जहां रिस्पॉन्स इकट्ठा किया जाता है।

चरण 6: क्वेरी आकार, सेमेंटिक्स और प्रोडक्शन प्रभाव को सत्यापित करें

खाली परिणाम, एक पंक्ति, दोहराई गई कस्टमर IDs, सभी अद्वितीय कस्टमर IDs, एक गायब वैकल्पिक कस्टमर और अधिकतम अनुमत पेज आकार के साथ एक रिग्रेशन मैट्रिक्स बनाएं। रिस्पॉन्स क्रम, IDs, नल व्यवहार, टेनेंट आइसोलेशन और एक स्थिर क्वेरी बजट का दावा करें। दो-क्वेरी योजना के लिए, 10 और 40 के पेजों को चुने गए बैच बाउंड के तहत दोनों में दो स्टेटमेंट्स का उपयोग करना चाहिए।

फिर कुल रिक्वेस्ट लेटेंसी, प्रति रिक्वेस्ट डेटाबेस स्पैन, लौटाई गई पंक्तियों और बाइट्स, कनेक्शन-पूल अधिभोग और डेटाबेस लोड के लिए प्रतिनिधि प्रोडक्शन-जैसे डेटा की तुलना करें। एक JOIN जो 51 स्टेटमेंट्स को घटाकर एक कर देता है लेकिन एक विशाल दोहराया गया पेलोड लौटाता है, वह एक अलग मीट्रिक के तहत रिग्रेशन हो सकता है। एंडपॉइंट द्वारा रोल आउट करें, क्वेरी-संख्या वितरण देखें, और एक ट्रेस नमूना बनाए रखें जो लेज़ी लोडिंग के फिर से प्रकट होने पर कॉल साइट की पहचान कर सके।

उच्च-गुणवत्ता वाला नमूना उत्तर

"साक्ष्य एक धीमी योजना के बजाय क्वेरी प्रवर्धन की ओर इशारा करते हैं। मैं एक रिक्वेस्ट ट्रेस से शुरुआत करूँगा और कॉल साइट द्वारा नॉर्मलाइज़्ड SQL को समूहित करूँगा। यदि 50 का एक पेज एक ऑर्डर क्वेरी और 50 कस्टमर प्राइमरी-की लुकअप दिखाता है, और फिर 10, 20 और 40 के पेज 11, 21 और 41 स्टेटमेंट उत्पन्न करते हैं, तो मैं दिखा सकता हूँ कि डेटाबेस का काम प्रति पैरेंट पंक्ति एक बार बढ़ता है।

इसे ठीक करने से पहले, मैं अनुबंध को बनाए रखूँगा: टेनेंट प्रेडिकेट्स, ऑर्डर IDs, नियतात्मक क्रम, पेज सीमा, आवश्यक कस्टमर फ़ील्ड और गायब-कस्टमर व्यवहार। चूंकि यह एक संकीर्ण मैनी-टू-वन लुकअप है, इसलिए JOIN एक अच्छा पहला उम्मीदवार है। एक दो-क्वेरी select-in लोड भी मान्य है: ऑर्डर पेज फ़ेच करें, कस्टमर IDs को डिडुप्लिकेट करें, उन कस्टमर्स को एक सेट क्वेरी में लोड करें, और ID द्वारा मैप करें। मैं जनरेट किए गए SQL, पेलोड चौड़ाई और कंसिस्टेंसी आवश्यकताओं के आधार पर उनके बीच चयन करूँगा।

यदि संबंध एक बड़ा वन-टू-मेनी कलेक्शन होता, तो मैं पहले ऑर्डर्स को पेज करता और दूसरी क्वेरी में आइटम्स को बैच करता। यह जॉइन्ड-पंक्ति गुणन को पेजिनेशन बदलने से बचाता है। मैं प्रत्येक एसोसिएशन को विश्व स्तर पर ईगर नहीं बनाऊँगा; यह ओवरफेच कर सकता है और कुछ ORM क्वेरी आकार अभी भी सेकेंडरी सेलेक्ट्स जारी करते हैं।

रिग्रेशन टेस्ट खाली, दोहराए गए-ID, अद्वितीय-ID, गायब-संबंध और अधिकतम-पेज मामलों को चलाएगा। यह समान IDs, क्रम, ऑथराइज़ेशन और नल व्यवहार के साथ-साथ एक स्थिर स्टेटमेंट बजट का दावा करेगा। रोलआउट के बाद मैं केवल धीमे व्यक्तिगत बयानों के बजाय प्रति रिक्वेस्ट डेटाबेस स्पैन और कुल लेटेंसी की निगरानी करूँगा। यह परफॉरमेंस फिक्स और अपरिवर्तित परिणाम दोनों को साबित करता है।"

सामान्य गलतियाँ

  • दोहराए गए कस्टमर लुकअप में एक इंडेक्स जोड़ना → प्रत्येक लुकअप पहले से ही एक प्राइमरी-की इंडेक्स का उपयोग कर सकता है, जबकि रिक्वेस्ट अभी भी प्रति ऑर्डर एक राउंडट्रिप करती है → एक्सेस पैटर्न को मापें और बदलें।
  • ग्लोबल ईगर लोडिंग सक्षम करना → असंबंधित एंडपॉइंट्स ओवरफेच करते हैं, और ORM-विशिष्ट ईगर व्यवहार अभी भी सेकेंडरी स्टेटमेंट्स जारी कर सकता है → एंडपॉइंट-विशिष्ट प्रोजेक्शन या लोडिंग योजना का उपयोग करें।
  • प्रत्येक संबंध को जॉइन करना → वन-टू-मेनी कलेक्शन्स पंक्तियों को गुणा करते हैं, पैरेंट डेटा को दोहराते हैं, और पेज सीमाओं को दूषित कर सकते हैं → पहले पैरेंट्स को पेज करें और बड़े कलेक्शन्स को बैच करें।
  • समाधान के रूप में प्रक्रिया-व्यापी कैश का उपयोग करना → कोल्ड या अद्वितीय IDs अभी भी रैखिक क्वेरीज़ उत्पन्न करते हैं, और पुराना या क्रॉस-टेनेंट डेटा एक नया जोखिम बन जाता है → कैश हिट से स्वतंत्र रूप से क्वेरी संख्या को सीमित करें।
  • केवल धीमे स्टेटमेंट्स की गणना करना → दर्जनों तेज़ क्वेरीज़ राउंडट्रिप और कनेक्शन की खपत करते हुए थ्रेशोल्ड-आधारित स्लो-क्वेरी लॉग से बच जाती हैं → रिक्वेस्ट और फ़िंगरप्रिंट द्वारा स्पैन एकत्र करें।
  • बैच क्वेरी में सुरक्षा प्रेडिकेट्स छोड़ना → ऑप्टिमाइज़ेशन किसी अन्य टेनेंट से संबंधित पंक्ति लोड कर सकता है → ऑथराइज़ेशन और सॉफ्ट-डिलीट फ़िल्टर को स्पष्ट रूप से बनाए रखें।
  • केवल कम लेटेंसी का दावा करना → टाइमिंग परीक्षण शोरगुल वाले होते हैं और वार्म कैश के साथ पास हो सकते हैं → एक स्थिर क्वेरी बजट और रिस्पॉन्स समतुल्यता का दावा करें, फिर लेटेंसी को अलग से मापें।
  • यह मानना कि दो क्वेरीज़ एक स्नैपशॉट के बराबर हैं → सामान्य आइसोलेशन व्यवहार के तहत स्टेटमेंट्स के बीच समवर्ती अपडेट दिखाई दे सकते हैं → जब अनुबंध को पॉइंट-इन-टाइम कंसिस्टेंसी की आवश्यकता हो तो ट्रांजेक्शन स्नैपशॉट या एक स्टेटमेंट चुनें।

फॉलो-अप प्रश्न और उत्तर

फॉलो-अप 1: JOIN दो-क्वेरी बैच से बेहतर कब होता है?

JOIN एक संकीर्ण मैनी-टू-वन या वन-टू-वन संबंध के लिए आकर्षक है, जब एकल-स्टेटमेंट स्नैपशॉट सेमेंटिक्स मायने रखते हैं और पंक्ति गुणन सीमित होता है। एक बैच तब आकर्षक होता है जब पैरेंट पेजिनेशन को अलग रखा जाना चाहिए, संबंधित डेटा एक कलेक्शन होता है, या जॉइन चौड़े पैरेंट कॉलम को दोहराता है। उत्सर्जित SQL और लौटाए गए बाइट्स का निरीक्षण करें; केवल स्टेटमेंट संख्या ही निर्णय नहीं लेती है।

फॉलो-अप 2: क्या होगा यदि 50 ऑर्डर केवल तीन कस्टमर्स को संदर्भित करते हैं?

एक रिक्वेस्ट-स्कोप्ड आइडेंटिटी मैप सामान्य (naive) पथ को चार स्टेटमेंट्स तक कम कर सकता है, लेकिन यह डेटा पर निर्भर रहता है। तीन IDs को डिडुप्लिकेट करें और एक सेट क्वेरी जारी करें ताकि नियोजित संख्या दो हो। शुद्धता या टेनेंट आइसोलेशन के लिए क्रॉस-रिक्वेस्ट कैश पर भरोसा न करें।

फॉलो-अप 3: आप GraphQL-स्टाइल नेस्टेड रिज़ॉल्वर में N+1 को कैसे पकड़ेंगे?

एक रिक्वेस्ट निष्पादन के दौरान रिलेशनशिप कुंजियों को एकत्र करें और फ़ील्ड्स को हल करने से पहले एक रिक्वेस्ट-स्कोप्ड बैच भेजें। पंक्तियों को मूल कुंजी अनुक्रम में वापस मैप करके परिणाम क्रम को सुरक्षित रखें और गायब कुंजियों को स्पष्ट रूप से प्रस्तुत करें। रिग्रेशन टेस्ट को कई पैरेंट्स के लिए नेस्टेड फ़ील्ड का अनुरोध करना चाहिए और एक सीमित स्टेटमेंट संख्या का दावा करना चाहिए; फ़ील्ड को छोड़ने से संबंधित क्वेरी से बचा जाना चाहिए।

फॉलो-अप 4: क्या होगा यदि बैच में एक क्वेरी द्वारा ले जाने से अधिक IDs हों?

डिडुप्लिकेट की गई IDs को डेटाबेस और ड्राइवर की बाधाओं से चुने गए सीमित चंक्स में विभाजित करें। मॉडल B चंक्स के लिए 1 + B स्टेटमेंट बन जाता है, इसलिए परीक्षणों को बिना शर्त दो के बजाय अपेक्षित सीमा का दावा करना चाहिए। यदि साधारण एंडपॉइंट पेजों को कई चंक्स की आवश्यकता होती है, तो पेज को छोटा करें या डेटा आकार पर पुनर्विचार करें।

फॉलो-अप 5: क्वेरी संख्या तय हो गई है, लेकिन लेटेंसी में मुश्किल से सुधार होता है। आगे क्या?

दूसरा समाधान प्रस्तावित करने से पहले डेटाबेस समय, नेटवर्क समय, सीरियलाइज़ेशन, लौटाई गई पंक्तियों और बाइट्स, लॉक वेट और पूल कतार की तुलना करें। नए जॉइन्ड या बैच किए गए स्टेटमेंट को स्वयं एक इंडेक्स की आवश्यकता हो सकती है, बहुत अधिक डेटा वापस कर सकता है, या एंड-टू-एंड लेटेंसी पर हावी नहीं हो सकता है। यदि यह रैखिक प्रवर्धन को हटाता है तो N+1 सुधार को बनाए रखें, लेकिन नए सबूतों के साथ शेष बाधा (bottleneck) का डायग्नोसिस करें।

सार्वजनिक स्रोत

संबंधित प्रश्न