2012-09-17 6 views
5

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

यहां ब्रेकडाउन है। मूल प्रयास किया गया था इस:

var logs = 
    (from record in dataContext.someTable 
    where [index is appropriate] 
    select record); 

foreach(linqEntity l in logs) 
{ 
    // Do stuff with data from l 
} 

यह बहुत तेजी से है, और एक अच्छा दर पर धाराओं, लेकिन समस्या यह है कि आवेदन की स्मृति उपयोग ऊपर चलती है कभी नहीं बंद हो जाता है। मेरा अनुमान है कि LINQ से SQL इकाइयों को स्मृति में चारों ओर रखा जा रहा है और ठीक से निपटान नहीं किया जा रहा है। तो Out of memory when creating a lot of objects C# पढ़ने के बाद, मैंने निम्नलिखित दृष्टिकोण की कोशिश की। ऐसा लगता है कि Skip/Take प्रतिमान है कि कई लोग स्मृति की बचत की अतिरिक्त सुविधा के साथ उपयोग करते हैं।

ध्यान दें कि _conn पहले से बनाया गया है, और प्रत्येक क्वेरी के लिए एक अस्थायी डेटा संदर्भ बनाया गया है, जिसके परिणामस्वरूप संबद्ध संस्थाएं कचरा एकत्रित होती हैं।

int skipAmount = 0; 
bool finished = false; 

while (!finished) 
{ 
    // Trick to allow for automatic garbage collection while iterating through the DB 
    using (var tempDataContext = new MyDataContext(_conn) {CommandTimeout = 600}) 
    {    
     var query = 
      (from record in tempDataContext.someTable 
      where [index is appropriate] 
      select record); 

     List<workerLog> logs = query.Skip(skipAmount).Take(BatchSize).ToList(); 
     if (logs.Count == 0) 
     { 
      finished = true; 
      continue; 
     } 

     foreach(linqEntity l in logs) 
     { 
      // Do stuff with data from l 
     } 

     skipAmount += logs.Count; 
    } 
} 

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

मैं LINQ के साथ ऐसा करने के लिए एक रास्ता मुझे पेजिंग द्वारा सीमित मेमोरी उपयोग की अनुमति देता है कि खोजने के लिए नहीं कर पा रहे डेटा, और फिर भी अभी भी प्रत्येक पृष्ठ निरंतर समय में लोड होता है। क्या यह ठीक से करने का कोई तरीका है? मेरा झुकाव यह है कि डेटाकॉन्टेक्स्ट को ऊपर दिए गए पहले दृष्टिकोण में वस्तु के बारे में स्पष्ट रूप से भूलने के लिए कुछ तरीका हो सकता है, लेकिन मुझे यह नहीं पता कि यह कैसे किया जाए।

+0

"मेरे पास एक विशाल तालिका है जिसे मुझे एक निश्चित क्रम पर पढ़ने और कुछ समग्र आंकड़ों की गणना करने की आवश्यकता है।" - इसे टीएसक्यूएल में सर्वर पर करें .... यही वह अच्छा है! –

+0

नहीं, आंकड़े उससे अधिक जटिल हैं, और SQL क्वेरी के साथ computable नहीं हैं। डेटा को एक निश्चित क्रम में और फिर अस्थायी रूप से सही, आदि की गणना की जाने वाली चीज़ों की आवश्यकता होती है। –

+0

"नहीं, आंकड़े उससे अधिक जटिल हैं, और SQL क्वेरी के साथ गणना नहीं कर रहे हैं" - वास्तव में? क्या एक पूर्ण उदाहरण देना संभव है? –

उत्तर

15

कुछ स्ट्रॉ में पागलपन के बाद, मैंने पाया कि DataContext का ObjectTrackingEnabled = false डॉक्टर द्वारा आदेश दिया गया हो सकता है। यह आश्चर्य की बात नहीं है, विशेष रूप से इस तरह के केवल पढ़ने के मामले के लिए बनाया गया है।

using (var readOnlyDataContext = 
    new MyDataContext(_conn) {CommandTimeout = really_long, ObjectTrackingEnabled = false}) 
{             
    var logs = 
     (from record in readOnlyDataContext.someTable 
     where [index is appropriate] 
     select record); 

    foreach(linqEntity l in logs) 
    { 
     // Do stuff with data from l 
    }     
} 

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

वस्तु बंद पर नज़र रखने के मोड़ के बारे में एक चेतावनी: मुझे पता चला कि जब आपको अनेक समवर्ती एक ही DataContext के साथ पढ़ता करने की कोशिश, तुम नहीं त्रुटि There is already an open DataReader associated with this Command which must be closed first. आवेदन सिर्फ चला जाता है एक अनंत लूप में 100% के साथ मिलता है सि पि यु का उपयोग। मुझे यकीन नहीं है कि यह एक सी # बग या एक सुविधा है।

+0

बहुत उपयोगी पोस्ट! +2 – craastad

+0

मुझे बिल्कुल वही समस्या थी, 1 एम पंक्तियों में पढ़ना, और स्मृति से बाहर चलना। "ऑब्जेक्टट्रैकिंग सक्षम" के साथ झूठी पर सेट किया गया, कचरा संग्रह * किया गया * इस फ़ंक्शन का उपयोग करने वाली मेमोरी को मुक्त करें। इसके बिना, लगभग 300 एमबी मेमोरी जारी नहीं की जा रही थी। तो यह छोटी सेटिंग एक बड़ा प्रभाव डाल सकती है। –

संबंधित मुद्दे