2014-10-21 5 views
5

मैं निम्नलिखित समस्या का सामना कर रहा हूँ:नकली चाबी अपवाद से बचने के लिए कैसे कुशलतापूर्वक

मैं एसक्यूएल सर्वर कई बाहरी डेटाबेस के साथ सिंक्रनाइज़ में एक टेबल रखने की कोशिश कर रहा हूँ। इन बाहरी डेटाबेस में साझा अनन्य प्राथमिक कुंजी नहीं है, इसलिए स्थानीय तालिका में एक साधारण पूर्णांक पीके है।

अब तिथि करने के लिए निम्नलिखित किया जाता है ऊपर स्थानीय तालिका रखने के लिए:

  1. बाहरी डेटाबेस पूछे जाते हैं।
  2. डेटा स्थानीय तालिका के लिए मान्य डेटा में परिवर्तित किया गया है।
  3. स्थानीय तालिका में डेटा लिखने का प्रयास करने के लिए एक डालने का उपयोग किया जाता है।
  4. यदि सम्मिलित एक डुप्लिकेट प्रविष्टि अपवाद देता है, तो पीके को एक चयनित क्वेरी द्वारा खोजा जाएगा और डेटा को अद्यतन क्वेरी द्वारा तालिका में लिखा जाएगा।
  5. एक और तालिका डाली गई या अद्यतन पंक्ति के पीके का उपयोग करके संशोधित की जाती है।

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

मैं इस प्रभाव से कैसे बच सकता हूं? मैं एक संग्रहीत प्रक्रिया का उपयोग नहीं करना चाहता क्योंकि मैं कोड द्वारा प्रबंधित क्वेरी को रखना चाहता हूं और संस्करण नियंत्रण में शामिल हूं।

मैंने विलय देखा है लेकिन मैंने बहुत से लोगों को इसके साथ मुद्दों की रिपोर्टिंग देखी है।

मुझे लगता है कि मुझे अपरिपक्व रूप का उपयोग करने की आवश्यकता है, लेकिन मुझे यकीन नहीं है कि डीबी द्वारा प्रबंधित पीके के साथ इसे कैसे किया जाए।

tl; dr: मुझे जो चाहिए वह एक क्वेरी है जो मुझे या तो पंक्ति डालने या अपडेट करने की अनुमति देगी (डुप्लिकेट कुंजी के आधार पर या नहीं) जो हमेशा पंक्ति के पीके को वापस कर देगी।

+2

MERGE कथन SQL सर्वर –

+0

@SteveFord के लिए अपर कमांड है, मुझे यह पता है लेकिन इसकी धीमी और/या छोटी गाड़ी की रिपोर्टें हैं। क्या यह अब मामला नहीं है? देखें: http://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/ http://www.sqlservercentral.com/Forums/Topic1465931-391-1.aspx –

+1

निष्पक्ष पर्याप्त @ माइक-वैन-लेउवेन एक वैकल्पिक दृष्टिकोण एक टेम्पलेट तालिका में अद्यतन पंक्तियों को कैप्चर करने के लिए पहले OUTPUT कथन का उपयोग करके अद्यतन करने के लिए होगा। फिर एक इंसर्ट करें ... चुनें .... जहां मौजूद नहीं है (चुनें * आकर्षक से) –

उत्तर

2

मेरे पास एक कार्यान्वयन है जिसे मैंने पहले किया था। आप इसे उपयोगी पा सकते हैं या नहीं।

इस तरह यह काम करता है ... मैं एक मॉडल ऑब्जेक्ट का उपयोग करके स्मृति में बाहरी और स्थानीय दोनों डेटा लोड करता हूं जो दोनों के लिए काम करेगा। उदाहरण के लिए ...

public class Person 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string PhoneNumber { get; set; } 
    public string Address { get; set; } 

    // This comparer will be used to find records that exist or don't exist. 
    public class KeyFieldComparer : IEqualityComparer<Person> 
    { 
     public bool Equals(Person p1, Person p2) 
     { 
      return p1.FirstName == p2.FirstName && p1.LastName == p2.LastName; 
     } 

     public int GetHashCode(Person p) 
     { 
      return p.FirstName.GetHashCode()^p.LastName.GetHashCode(); 
     } 
    } 

    // This comparer will be used to find records that are outdated and need to be updated. 
    public class OutdatedComparer : IEqualityComparer<Person> 
    { 
     public bool Equals(Person p1, Person p2) 
     { 
      return p1.FirstName == p2.FirstName && p1.LastName == p2.LastName && (p1.PhoneNumber != p2.PhoneNumber || p1.Address != p2.Address); 
     } 

     public int GetHashCode(Person p) 
     { 
      return p.FirstName.GetHashCode()^p.LastName.GetHashCode(); 
     } 
    } 
} 

हमें आपके रिकॉर्ड के विशिष्ट रूप से पहचानने के लिए कुछ तरीका होना चाहिए। इस उदाहरण में यह FirstName और LastName है (मुझे पता है कि यह बहुत अनूठा नहीं है लेकिन सादगी के लिए आइए यह दिखाएं कि यह अच्छी तरह से काम करता है)। IEqualityComparer<> सूचियों को स्मृति में लोड होने पर पुराने और नए रिकॉर्ड खोजने का काम करेगा।

अब हम बस अलग मौजूदा पुराना रिकॉर्ड और इस तरह नया रिकॉर्ड ...

List<Person> local = loadLocalRecords(); 
List<Person> external = loadExternalRecords(); 

var newRecordsToInsert = external.Except(local, new Person.KeyFieldComparer()); 

var outdatedRecordsToUpdate = local.Intersect(external, new Person.OutdatedComparer()); 

मुझे आशा है कि यह समझ में आता है। यदि आपके पास हैं तो मैं सवालों का जवाब दे सकता हूं। इस विधि के बारे में अच्छी बात यह है कि यह डेटाबेस में कम से कम हिट के साथ नौकरी करता है (मुझे लगता है)। बुरी बात यह है कि इसे सब कुछ स्मृति में लोड करना है जो आपके लिए व्यावहारिक नहीं हो सकता है। लेकिन एक समस्या होने के लिए आपके टेबल आकार को बड़ा होना चाहिए। कितने कॉलम के आधार पर कहीं कुछ मिलियन रिकॉर्ड से ऊपर है।

+0

इस उत्तर के लिए धन्यवाद, यह एक दिलचस्प दृष्टिकोण है। मैंने एक समान समाधान के बारे में सोचा है लेकिन मुझे लगता है कि मैं पहले विलय करने की कोशिश करूंगा। अपवादों के साथ वर्तमान समाधान बनाम इस समाधान की दक्षता को देखने के लिए मैं थोड़ा परीक्षण कर सकता हूं। एक मजेदार प्रयोग होगा। मेमोरी वास्तव में मेरी स्थिति के लिए कोई समस्या नहीं होगी, मैं भागों में डेटा लोड कर रहा हूं। –

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