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

DuckDB क्वेरी के आउट-ऑफ-मेमोरी (OOM) एरर्स का निदान आप कैसे करते हैं?

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

प्रश्न

सीमित संसाधनों वाले होस्ट पर एक DuckDB क्वेरी मेमोरी समाप्त (OOM) कर देती है या अत्यधिक टेम्पररी फ़ाइलें बनाती है। आप इसका निदान, ट्यूनिंग और शुद्धता (correctness) कैसे साबित करेंगे?

प्रॉम्प्ट और दायरा

आप एक लोकल एनालिटिक्स टास्क के ओनर हैं। DuckDB Parquet फ़ाइलों को पढ़ता है और मल्टी-टेबल JOINs, GROUP BY ऑपरेशन्स और विंडो फ़ंक्शन्स चलाता है। जैसे-जैसे डेटा बढ़ता है, यह टास्क या तो Out of Memory रिपोर्ट करता है या कई टेम्पररी फ़ाइलें बनाकर टाइमआउट हो जाता है। अपने निदान का क्रम, पैरामीटर परिवर्तन, SQL रीराइट्स और वेरिफिकेशन प्लान स्पष्ट करें।

यह परिदृश्य डेटा-इंजीनियरिंग, एनालिटिक्स-इंजीनियरिंग और एम्बेडेड OLAP इंटरव्यूज के लिए उपयुक्त है। उत्तर साक्ष्य-आधारित (evidence-led) होना चाहिए; "मेमोरी जोड़ना" या "बड़ी मशीन खरीदना" कोई निदान नहीं है।

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

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

उत्तर देने से पहले स्पष्टीकरण प्रश्न

  1. क्या विफलता स्कैनिंग, JOIN, एग्रीगेशन, सॉर्टिंग या विंडो के दौरान होती है? क्या यह DuckDB एरर है या ऑपरेटिंग-सिस्टम किल?
  2. DuckDB वर्शन, थ्रेड काउंट, memory_limit, टेम्पररी-डायरेक्टरी पाथ और उपलब्ध डिस्क स्पेस क्या हैं?
  3. क्या इनपुट Parquet/CSV है, कॉलम टाइप्स और पार्टीशन लेआउट क्या हैं, और क्या प्रेडिकेट्स को पुश डाउन किया जा सकता है?
  4. क्या क्वेरी में हाई-कार्डिनैलिटी GROUP BY, सटीक DISTINCT, वाइड JOINs, ORDER BY, विंडोज़, list/string_agg या PIVOT शामिल हैं?
  5. क्या परिणाम को बैचों में प्रोसेस, प्री-एग्रीगेट, एप्रोक्सीमेट या इनपुट ऑर्डर को सुरक्षित रखे बिना लौटाया जा सकता है?

30-सेकंड उत्तर फ्रेमवर्क

मैं पहले उस ऑपरेटर और रिसोर्स की पहचान करता हूँ जो समाप्त हो गए हैं, फिर EXPLAIN ANALYZE, मेमोरी स्नैपशॉट्स और टेम्पररी-डायरेक्टरी मेट्रिक्स के साथ एक बेसलाइन स्थापित करता हूँ। यदि कोई हाई-कार्डिनैलिटी एग्रीगेट, JOIN, सॉर्ट या विंडो ब्लॉकिंग स्टेट बनाती है, तो मैं स्कैन की गई पंक्तियों और कॉलमों को कम करता हूँ और कॉनक्रेन्सी कम करने, सुरक्षित मेमोरी लिमिट सेट करने और स्पिल डायरेक्टरी को वैलिडेट करने से पहले फ़िल्टर या जॉइन कंडीशन्स को ठीक करता हूँ। अंत में, मैं फिक्स्ड और पूर्ण इनपुट्स पर रो काउंट्स, की यूनिकनेस, एग्रीगेट्स और लेटेंसी की तुलना करता हूँ ताकि ऑप्टिमाइज़ेशन तेज़ और सेमेंटिक रूप से सुरक्षित दोनों हो।

चरण-दर-चरण डीप डाइव

1. मेमोरी विफलता को टेम्पररी-डिस्क विफलता से अलग करें

एरर टेक्स्ट, प्रोसेस एग्जिट रीज़न, पीक RSS, DuckDB वर्शन, थ्रेड काउंट और क्वेरी फिंगरप्रिंट रिकॉर्ड करें। DuckDB उपलब्ध मेमोरी के एक हिस्से को लिमिट के रूप में रिज़र्व करता है, लेकिन ऑपरेटिंग-सिस्टम OOM, कंटेनर कैप, अनराइटेबल टेम्पररी डायरेक्टरी या भरी हुई डिस्क भी समान दिख सकती है। SQL बदलने से पहले cgroup/कंटेनर लिमिट्स, कैपेसिटी और परमिशन्स को सत्यापित करें।

2. प्लान में ब्लॉकिंग ऑपरेटर को खोजें

जॉइन ऑर्डर और प्रेडिकेट पुशडाउन का निरीक्षण करने के लिए EXPLAIN का उपयोग करें, फिर वास्तविक पंक्तियों, टाइमिंग और रनटाइम स्टेट के लिए EXPLAIN ANALYZE का उपयोग करें। स्कैन आमतौर पर चंक्स को प्रोसेस करते हैं, जबकि GROUP BY, JOIN, ORDER BY, विंडोज़ और सटीक DISTINCT हैश टेबल, सॉर्ट बफ़र्स या फ्रेम्स को बनाए रखते हैं। यदि कोई गलत जॉइन की (key) पंक्तियों को कई गुना बढ़ा देती है, तो मेमोरी पर चर्चा करने से पहले इसके सेमेंटिक्स को ठीक करें।

3. रिसोर्सेज को ट्यून करने से पहले वर्किंग सेट को कम करें

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

4. थ्रेड्स, मेमोरी और स्पिलिंग को सेट और सत्यापित करें

अधिक थ्रेड्स कई ऑपरेटर्स को एक साथ स्टेट होल्ड करने के लिए बाध्य कर सकते हैं, इसलिए सीमित होस्ट पर threads को कम करें। सिस्टम हेडरूम छोड़ने के लिए memory_limit को कंटेनर बजट से नीचे रखें; इसे केवल बढ़ाने से DuckDB एरर OS किल में बदल सकता है। स्पिलिंग के लिए, ज्ञात क्षमता वाली एक राइटेबल, तेज़ लोकल डिस्क का उपयोग करें। एक नियंत्रित प्रयोग इसका उपयोग कर सकता है:

sql
SET threads = 4;
SET memory_limit = '4GB';
SET temp_directory = '/var/tmp/duckdb_swap';
SET preserve_insertion_order = false;
EXPLAIN ANALYZE
SELECT customer_id, date_trunc('day', event_time) AS day, sum(amount) AS total
FROM read_parquet('events/*.parquet')
WHERE event_time >= DATE '2026-01-01'
GROUP BY customer_id, day;

preserve_insertion_order को केवल तभी अक्षम करें जब व्यावसायिक परिणाम इनपुट ऑर्डर पर निर्भर न हो। इंडेक्स और कुछ इंटरमीडिएट स्टेट्स आवश्यक रूप से बफ़र मैनेजर द्वारा नियंत्रित नहीं होते हैं, इसलिए memory_limit एक यूनिवर्सल हार्ड गार्ड नहीं है।

5. स्पिल व्यवहार और ऑपरेटर सीमाओं की पहचान करें

स्पिलिंग कई बड़े GROUP BY, JOIN, सॉर्ट और विंडो वर्कलोड्स का समर्थन करती है, लेकिन यह I/O जोड़ती है। चेन्ड ब्लॉकिंग ऑपरेटर्स, विशाल लिस्ट एग्रीगेट्स, string_agg, कुछ होलिस्टिक एग्रीगेट्स और PIVOT को अभी भी बड़े अविभाज्य स्टेट की आवश्यकता हो सकती है। यदि टेम्पररी डायरेक्टरी अप्रत्याशित रूप से बढ़ती है, तो temp_directory, max_temp_directory_size, डिस्क थ्रूपुट और क्लीनअप की जांच करें। जब स्पिलिंग मदद न कर सके, तो बैचिंग पर वापस जाएं या SQL शेप को दोबारा लिखें।

6. परिणाम और परफॉर्मेंस रिग्रेशन के साथ समापन करें

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

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

मैं इस घटना को ऑपरेटर स्टेट, कॉन्फ़िगरेशन कैपेसिटी या बाहरी वातावरण के रूप में वर्गीकृत करता हूँ। सबसे पहले मैं वर्शन, क्वेरी, इनपुट स्नैपशॉट, कंटेनर मेमोरी और टेम्पररी-डिस्क साक्ष्य को सुरक्षित रखता हूँ, फिर पीक का पता लगाने के लिए EXPLAIN ANALYZE का उपयोग करता हूँ। हाई-कार्डिनैलिटी GROUP BY, गलत मेनी-टू-मेनी JOIN, सॉर्ट या विंडो के लिए, मैं कार्डिनैलिटी और प्रेडिकेट पुशडाउन की जांच करता हूँ, कॉलम्स और पंक्तियों को कम करता हूँ, और उपयुक्त होने पर प्री-एग्रीगेट करता हूँ; मैं केवल memory_limit बढ़ाकर जॉइन एक्सप्लोजन को नहीं छुपाता।

इसके बाद, मैं थ्रेड कॉनक्रेन्सी को मापे गए सुरक्षित स्तर तक कम करता हूँ, memory_limit से नीचे सिस्टम हेडरूम छोड़ता हूँ, और temp_directory को स्पष्ट क्षमता और परमिशन्स वाली डिस्क पर रखता हूँ। मैं preserve_insertion_order को केवल तभी अक्षम करता हूँ जब ऑर्डर कॉन्ट्रैक्चुअल न हो। मैं पीक मेमोरी, स्पिल बाइट्स और रनटाइम को मापता हूँ, और जांचता हूँ कि टेम्पररी उपयोग कोटा के भीतर रहे। लिस्ट, बहुत बड़े स्ट्रिंग या PIVOT स्टेट्स के लिए जिन्हें प्रभावी ढंग से विभाजित नहीं किया जा सकता है, मैं स्टेज्ड परिणामों का उपयोग करता हूँ या क्वेरी स्ट्रक्चर पर पुनर्विचार करता हूँ।

अंत में, रिलीज़ से पहले मैं फिक्स्ड और पूरे डेटा पर रो काउंट्स, की यूनिकनेस, एग्रीगेट चेकसम, बाउंड्री पार्टीशन्स और NULL व्यवहार की तुलना करता हूँ। यह साबित करता है कि OOM समाप्त हो गया है और परिणाम के सेमेंटिक्स सुरक्षित रहे हैं।

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

केवल memory_limit बढ़ाना

कंटेनर कैप, सिस्टम हेडरूम और नॉन-बफ़र-मैनेज्ड मेमोरी की जांच किए बिना, विफलता DuckDB से ऑपरेटिंग सिस्टम में स्थानांतरित हो सकती है।

यह मान लेना कि प्रत्येक ऑपरेटर स्पिल कर सकता है

विशिष्ट ऑपरेटर और वर्शन की पुष्टि करें। कुछ लिस्ट, स्ट्रिंग, होलिस्टिक एग्रीगेट्स और PIVOT स्टेट्स को अभी भी अविभाज्य मेमोरी की आवश्यकता होती है।

JOIN कार्डिनैलिटी और प्रेडिकेट पुशडाउन को अनदेखा करना

गैर-अद्वितीय कीज या देर से लगाए गए फ़िल्टर कई गुना अधिक इंटरमीडिएट डेटा बना सकते हैं; सेटिंग्स गलत क्वेरी स्ट्रक्चर को ठीक नहीं कर सकती हैं।

परिणाम रिग्रेशन के बिना सफलता मान लेना

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

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

फॉलो-अप 1: कम थ्रेड्स से कैसे मदद मिल सकती है?

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

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

हर स्टेट को पार्टीशन और स्पिल नहीं किया जा सकता है। अविभाज्य एग्रीगेट्स, अत्यधिक बड़ा जॉइन स्टेट, या डायरेक्टरी परमिशन्स और कोटा अभी भी विफल हो सकते हैं; प्लान, लिमिट्स और लॉग्स को मिलाकर विश्लेषण करें।

फॉलो-अप 3: इंसर्शन-ऑर्डर प्रिजर्वेशन को कब अक्षम किया जा सकता है?

केवल तब जब परिणाम और डाउनस्ट्रीम उपभोक्ता इनपुट ऑर्डर को एक अनुबंध के रूप में नहीं मानते हैं। इसके बाद डुप्लिकेट कीज, ऑर्डरिंग और LIMIT व्यवहार का रिग्रेशन परीक्षण करें।

फॉलो-अप 4: आप कैसे साबित करते हैं कि ट्यूनिंग ने परिणामों को सुरक्षित रखा?

वही इनपुट स्नैपशॉट चलाएं और रो काउंट्स, प्राइमरी-की सेट्स, ग्रुप काउंट्स, न्यूमेरिक चेकसम, NULL डिस्ट्रीब्यूशन और बाउंड्री पार्टीशन्स की तुलना करें। अनुमानित एग्रीगेट्स के लिए, एरर बजट बताएं और व्यावसायिक स्वीकृति प्राप्त करें।

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

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