2010-03-10 10 views
5

मैं SQL सर्वर से डेटा को संसाधित करने के लिए LinqToSQL का उपयोग कर रहा हूं ताकि इसे आगे की प्रक्रिया के लिए iSeries सर्वर में डंप कर सकें। More details on that hereतेजी से क्या है? स्ट्रक्चर सरणी या डेटाटेबल

मेरी समस्या यह है कि डेटा की उन 350 पंक्तियों को संसाधित करने में लगभग 1.25 मिनट लगते हैं। मैं अभी भी SQL सर्वर प्रोफाइलर से परिणामों को समझने की कोशिश कर रहा हूं, लेकिन प्रश्नों का एक टन चल रहा है।

using (CarteGraphDataDataContext db = new CarteGraphDataDataContext()) 
{ 
    var vehicles = from a in db.EquipmentMainGenerals 
        join b in db.EquipmentMainConditions on a.wdEquipmentMainGeneralOID equals b.wdEquipmentMainGeneralOID 
        where b.Retired == null 
        orderby a.VehicleId 
        select a; 

    et = new EquipmentTable[vehicles.Count()]; 

    foreach (var vehicle in vehicles) 
    { 
     // Move data to the array 

     // Rates 
     GetVehcileRates(vehicle.wdEquipmentMainGeneralOID); 

     // Build the costs accumulators 
     GetPartsAndOilCosts(vehicle.VehicleId); 
     GetAccidentAndOutRepairCosts(vehicle.wdEquipmentMainGeneralOID); 

     // Last Month's Accumulators 
     et[i].lastMonthActualGasOil = GetFuel(vehicle.wdEquipmentMainGeneralOID) + Convert.ToDecimal(oilCost); 
     et[i].lastMonthActualParts = Convert.ToDecimal(partsCost); 
     et[i].lastMonthActualLabor = GetLabor(vehicle.VehicleId); 
     et[i].lastMonthActualOutRepairs = Convert.ToDecimal(outRepairCosts); 
     et[i].lastMonthActualAccidentCosts = Convert.ToDecimal(accidentCosts); 

     // Move more data to the array 

     i++; 
    } 
} 

तरीकों जाओ सब के समान दिखाई:: यहाँ है कि मैं क्या कर रहा हूँ पर थोड़ा और अधिक विस्तार है

private void GetPartsAndOilCosts(string vehicleKey) 
{ 
    oilCost = 0; 
    partsCost = 0; 

    using (CarteGraphDataDataContext db = new CarteGraphDataDataContext()) 
    { 
     try 
     { 
     var costs = from a in db.WorkOrders 
        join b in db.MaterialLogs on a.WorkOrderId equals b.WorkOrder 
        join c in db.Materials on b.wdMaterialMainGeneralOID equals c.wdMaterialMainGeneralOID 
        where (monthBeginDate.Date <= a.WOClosedDate && a.WOClosedDate <= monthEndDate.Date) && a.EquipmentID == vehicleKey 
        group b by c.Fuel into d 
        select new 
          { 
           isFuel = d.Key, 
           totalCost = d.Sum(b => b.Cost) 
          }; 

      foreach (var cost in costs) 
      { 
      if (cost.isFuel == 1) 
      { 
       oilCost = (double)cost.totalCost * (1 + OVERHEAD_RATE); 
      } 
      else 
      { 
       partsCost = (double)cost.totalCost * (1 + OVERHEAD_RATE); 
      } 
      } 
     } 
     catch (InvalidOperationException e) 
     { 
      oilCost = 0; 
      partsCost = 0; 
     } 
    } 

    return; 
} 

मेरे सोच यहाँ डीबी के लिए क्वेरी की संख्या नीचे काटने है में तेजी लाने चाहिए प्रसंस्करण। यदि LINQ प्रत्येक रिकॉर्ड के लिए एक चयन करता है, तो मुझे पहले प्रत्येक रिकॉर्ड को स्मृति में लोड करने की आवश्यकता है।

मैं अब भी सामान्य रूप से सी # और ओओपी के साथ शुरुआत करने वाला हूं (मैं ज्यादातर आईएसरीज पर आरपीजी प्रोग्रामिंग करता हूं)। तो मुझे लगता है कि मैं कुछ बेवकूफ कर रहा हूँ। क्या आप मेरी मूर्खता को ठीक करने में मदद कर सकते हैं (कम से कम इस समस्या के साथ)?

अद्यतन: सोचा कि मैं वापस आऊंगा और जो मैंने खोजा है उस पर आपको अपडेट करूँगा। ऐसा लगता है कि डेटाबेस खराब डिजाइन किया गया था। जो कुछ भी LINQ पृष्ठभूमि में उत्पन्न कर रहा था वह अत्यधिक अक्षम कोड था। मैं यह नहीं कह रहा कि LINQ खराब है, यह सिर्फ इस डेटाबेस के लिए बुरा था। मैं एक साथ जल्दी से फेंक दिया .XSD सेटअप और प्रसंस्करण समय 1.25 मिनट से 15 सेकंड तक चला गया। एक बार जब मैं एक उचित रीडिज़ाइन करता हूं, तो मैं केवल अनुमान लगा सकता हूं कि मैं इसके कुछ और सेकंड बंद कर दूंगा। आप सभी के लिए धन्यवाद। मैं एक बेहतर डेटाबेस पर कुछ अन्य दिन LINQ फिर से कोशिश करूंगा।

+0

मेरे अपने 2 सेंट, डेटाटेबल्स के पास इस दशक में कोड में कोई भी स्थान नहीं है। –

उत्तर

7

कुछ चीजें है कि मैं अपने कोड में स्पॉट हैं:, तो आप उस क्वेरी के पुनर्लेखन के लिए चाहते हो सकता है

  1. आप 'var वाहनों' क्वेरी में प्रत्येक आइटम के लिए डेटाबेस कई बार क्वेरी जाता है कि कम डेटाबेस प्रश्नों की आवश्यकता है।
  2. जब आपको पूछे जाने वाले इकाई के सभी गुणों की आवश्यकता नहीं होती है, या उस इकाई की उप-इकाइयों की आवश्यकता होती है, तो प्रदर्शन के लिए आपके select में अनाम प्रकार का उपयोग करना बेहतर होता है। LINQ से SQL इसका विश्लेषण करेगा और आपके डेटाबेस से कम डेटा पुनर्प्राप्त करेगा। इस तरह का एक चयन इस तरह दिख सकता है: select new { a.VehicleId, a.Name }
  3. GetPartsAndOilCosts में क्वेरी LINQ क्वेरी में गणना cost.totalCost * (1 + OVERHEAD_RATE) डालकर अनुकूलित किया जा सकता है। इस तरह क्वेरी को पूरी तरह से डेटाबेस में निष्पादित किया जा सकता है, जो इसे बहुत तेज बनाना चाहिए।
  4. आप var vehicles क्वेरी पर Count() कर रहे हैं, लेकिन आप केवल सरणी के आकार को निर्धारित करने के लिए इसका उपयोग करते हैं। जबकि LINQ से SQL एक बहुत ही कुशल SELECT count(*) क्वेरी करेगा, यह डेटाबेस के लिए एक अतिरिक्त दौर यात्रा लेता है। इसके अलावा (आपके अलगाव स्तर के आधार पर) जब आप क्वेरी को फिर से शुरू करना शुरू करते हैं तो एक आइटम जोड़ा जा सकता है। उस स्थिति में आपकी सरणी बहुत छोटी है और ArrayIndexOutOfBoundsException फेंक दिया जाएगा। आप क्वेरी पर .ToArray() का उपयोग कर सकते हैं या List<EquipmentTable> बना सकते हैं और उस पर .ToArray() पर कॉल कर सकते हैं। यह सामान्य रूप से पर्याप्त तेज़ होगा, खासकर जब आपके पास इस संग्रह में केवल 380 आइटम हों और यह डेटाबेस (गिनती) के लिए अतिरिक्त राउंडट्रिप होने से निश्चित रूप से तेज़ होगा।
  5. जैसा कि आप शायद पहले से ही उम्मीद करते हैं, डेटाबेस क्वेरी की मात्रा वास्तविक समस्या है। स्ट्रक्चर सरणी या डेटाटेबल के बीच स्विचिंग बहुत अलग नहीं करेगी।
  6. आप जितने अधिक प्रश्नों को अनुकूलित कर सकते हैं, उन्हें छोड़कर प्रश्नों का विश्लेषण करना शुरू करें (एसक्यूएल प्रोफाइलर का उपयोग करके) और इंडेक्स ट्यूनिंग विज़ार्ड का उपयोग करके इन प्रश्नों को अनुकूलित करें। यह आपके लिए कुछ नई अनुक्रमणिका का प्रस्ताव देगा, जो चीजों को काफी तेज कर सकता है।

बिंदु # 1 के लिए एक छोटी सी अतिरिक्त स्पष्टीकरण। क्या आप यहाँ क्या कर रहे हैं इस तरह एक सा है: क्योंकि यह शीर्ष क्वेरी की प्रत्येक पंक्ति पर निष्पादित हो रहा है

क्या आप को पूरा करने के लिए प्रयास करना चाहिए, query2 सबक्वेरी दूर करने के लिए है। तो अगर आप कुछ इस तरह लग सकती है:

var query = 
    from x in A 
    from y in B 
    where x.Value == y.Value 
    select something; 

foreach (var row in query) 
{ 
} 
बेशक

इस उदाहरण साधारण है और वास्तविक जीवन में यह बहुत जटिल हो जाता है (जैसा कि आप पहले से ही देखा है)। आपके मामले में भी क्योंकि आपको उन 'उप-प्रश्नों' में से कई मिल गए हैं। यह आपको सही करने के लिए कुछ समय ले सकता है, खासकर LINQ से SQL के ज्ञान की कमी के साथ (जैसा आपने स्वयं कहा था)।

यदि आप इसे समझ नहीं सकते हैं, तो आप हमेशा स्टैक ओवरफ्लो पर फिर से पूछ सकते हैं, लेकिन कृपया अपनी समस्या को सबसे छोटी चीज़ पर पट्टी करना याद रखें, क्योंकि किसी की गड़बड़ी को पढ़ने में कोई मजा नहीं है (हमें नहीं मिल रहा है इसके लिए भुगतान किया गया) :-) शुभकामनाएँ।

+0

@Steven: क्षमा करें, मैं # 1 पर उलझन में हूँ। मुझे यकीन नहीं है कि यह कैसे करें। आपके सभी अन्य बिंदुओं में मैं देख रहा हूं। –

+0

@ माइक: मैंने अपना जवाब अपडेट किया। – Steven

+0

अद्यतन के लिए धन्यवाद। मैं इस पर गौर करूंगा। –

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