SQL सर्वर पर अद्यतन संग्रहीत संग्रह सम्मिलित करें


104

मैंने एक संग्रहीत खरीद लिखी है जो एक रिकॉर्ड मौजूद होने पर अपडेट करेगा, अन्यथा यह एक प्रविष्टि करेगा। यह कुछ इस तरह दिखता है:

update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)

इसे इस तरह से लिखने के पीछे मेरा तर्क यह है कि अपडेट जहां क्लॉज का उपयोग कर एक अंतर्निहित चयन करेगा और यदि वह 0 देता है तो इंसर्ट होगा।

इस तरह से करने का विकल्प एक चयन करना होगा और फिर लौटाई गई पंक्तियों की संख्या के आधार पर या तो एक अद्यतन करना या सम्मिलित करना होगा। यह मैंने अयोग्य माना क्योंकि यदि आप कोई अपडेट करते हैं तो यह 2 चयनों का कारण होगा (पहला स्पष्ट चयन कॉल और अपडेट के दूसरे में निहित)। यदि खरीद एक सम्मिलित करने के लिए थी, तो दक्षता में कोई अंतर नहीं होगा।

क्या मेरा तर्क यहाँ है? क्या यह है कि आप सम्मिलित सम्मिलित करें और एक संग्रहीत खरीद में अद्यतन कैसे करें?

जवाबों:


61

आपकी धारणा सही है, यह करने का सबसे इष्टतम तरीका है और इसे upsert / मर्ज कहा जाता है ।

UPSERT का महत्व - sqlservercentral.com से :

ऊपर उल्लिखित मामले में हर अपडेट के लिए हम तालिका से एक अतिरिक्त रीड निकाल रहे हैं यदि हम EXISTS के बजाय UPSERT का उपयोग करते हैं। सम्मिलित रूप से दुर्भाग्य से, UPSERT और IF EXISTS दोनों ही पटल पर समान संख्या में रीड का उपयोग करते हैं। इसलिए अस्तित्व की जांच केवल तभी की जानी चाहिए जब अतिरिक्त I / O को सही ठहराने का एक बहुत ही वैध कारण हो। चीजों को करने का अनुकूलित तरीका यह सुनिश्चित करना है कि आपके पास डीबी पर जितना संभव हो उतना कम पढ़े।

अद्यतन करने का प्रयास करने के लिए सबसे अच्छी रणनीति है। यदि कोई पंक्तियाँ अद्यतन से प्रभावित नहीं हैं, तो सम्मिलित करें। ज्यादातर परिस्थितियों में, पंक्ति पहले से मौजूद होगी और केवल एक I / O की आवश्यकता होगी।

संपादित करें : कृपया इस पैटर्न के साथ समस्याओं के बारे में जानने के लिए इस उत्तर और लिंक किए गए ब्लॉग पोस्ट की जांच करें और इसे सुरक्षित कैसे बनाएं।


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

54

कृपया मेरे ब्लॉग पर पोस्ट को एक अच्छे, सुरक्षित पैटर्न के लिए पढ़ें जिसे आप उपयोग कर सकते हैं। बहुत सारे विचार हैं, और इस प्रश्न पर स्वीकृत उत्तर सुरक्षित नहीं है।

एक त्वरित उत्तर के लिए निम्नलिखित पैटर्न का प्रयास करें। यह SQL 2000 और इसके बाद के संस्करण पर ठीक काम करेगा। SQL 2005 आपको त्रुटि हैंडलिंग देता है जो अन्य विकल्प खोलता है और SQL 2008 आपको एक MERGE कमांड देता है।

begin tran
   update t with (serializable)
   set hitCount = hitCount + 1
   where pk = @id
   if @@rowcount = 0
   begin
      insert t (pk, hitCount)
      values (@id,1)
   end
commit tran

1
आपके ब्लॉग पोस्ट में आप मौजूद चेक में मौजूद (अपकॉक, सीरियल करने योग्य) संकेत का उपयोग करके समाप्त होते हैं। हालाँकि, MSDN पढ़ने में कहा गया है: "UPDLOCK - निर्दिष्ट करता है कि लेन-देन के अपडेट होने तक अपडेट लॉक को रखा और आयोजित किया जा सकता है।" क्या इसका मतलब यह है कि क्रमिक संकेत बहुत ही कम है क्योंकि अपडेट लॉक वैसे भी शेष के लिए आयोजित किया जाएगा, या मुझे कुछ गलत समझा है?
डैन डेफ

10

यदि SQL Server 2000/2005 के साथ उपयोग किया जाना है तो मूल कोड को लेन-देन में संलग्न करने की आवश्यकता है ताकि यह सुनिश्चित हो सके कि डेटा समवर्ती परिदृश्य में सुसंगत रहे।

BEGIN TRANSACTION Upsert
update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)
COMMIT TRANSACTION Upsert

यह अतिरिक्त प्रदर्शन लागत को प्रभावित करेगा, लेकिन डेटा अखंडता को सुनिश्चित करेगा।

जोड़ें, जैसा कि पहले से ही सुझाव दिया गया है, उपलब्ध होने पर MERGE का उपयोग किया जाना चाहिए।



6

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

SET transaction isolation level SERIALIZABLE
BEGIN TRANSACTION Upsert
UPDATE myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
  begin
    INSERT into myTable (ID, Col1, Col2) values (@ID @col1, @col2)
  end
COMMIT TRANSACTION Upsert

शायद @@ एरर चेक और रोलबैक जोड़ना भी एक अच्छा विचार हो सकता है।


@ मनीष गोयल क्योंकि डेटाबेस में कई कमांड्स और पूर्वविधियाँ पैराल में चलती हैं। फिर अन्य थ्रेड अद्यतन चलाने के बाद और डालने से पहले एक पंक्ति सम्मिलित कर सकते हैं।
टॉमस टिन्तेरा

5

यदि आप SQL 2008 में मर्ज नहीं कर रहे हैं, तो आपको इसे इसमें बदलना होगा:

अगर @@ rowcount = 0 और @@ त्रुटि = 0

अन्यथा यदि अपडेट किसी कारण से विफल हो जाता है, तो यह बाद में डालने का प्रयास करेगा और क्योंकि विफल कथन पर पंक्ति पंक्ति 0 है


3

UPSERT का बड़ा प्रशंसक, वास्तव में प्रबंधन करने के लिए कोड में कटौती करता है। यहां एक और तरीका है जो मैं इसे करता हूं: इनपुट मापदंडों में से एक आईडी है, अगर आईडी NULL या 0 है, तो आप जानते हैं कि यह एक INSERT है, अन्यथा यह अपडेट है। मान लेता है कि अगर कोई आईडी है, तो सभी स्थितियों में काम नहीं करेगा, लेकिन यदि आप करते हैं तो निष्पादन में कटौती होगी।


2

संशोधित दीमा मालेंको पोस्ट:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 

BEGIN TRANSACTION UPSERT 

UPDATE MYTABLE 
SET    COL1 = @col1, 
       COL2 = @col2 
WHERE  ID = @ID 

IF @@rowcount = 0 
  BEGIN 
      INSERT INTO MYTABLE 
                  (ID, 
                   COL1, 
                   COL2) 
      VALUES      (@ID, 
                   @col1, 
                   @col2) 
  END 

IF @@Error > 0 
  BEGIN 
      INSERT INTO MYERRORTABLE 
                  (ID, 
                   COL1, 
                   COL2) 
      VALUES      (@ID, 
                   @col1, 
                   @col2) 
  END 

COMMIT TRANSACTION UPSERT 

आप त्रुटि को फंसा सकते हैं और रिकॉर्ड को एक असफल सम्मिलित तालिका में भेज सकते हैं।
मुझे ऐसा करने की आवश्यकता थी क्योंकि हम डब्ल्यूएसडीएल के माध्यम से जो भी डेटा भेज रहे हैं और यदि संभव हो तो आंतरिक रूप से इसे ठीक कर रहे हैं।


1

यदि आप एक विशिष्ट प्राथमिक कुंजी में पारित कर चुके हैं तो आपके तर्क में ध्वनि लगती है, लेकिन आप सम्मिलित होने से रोकने के लिए कुछ कोड जोड़ने पर विचार कर सकते हैं।

अन्यथा, यदि आप हमेशा एक प्रविष्टि कर रहे हैं यदि अद्यतन किसी भी रिकॉर्ड को प्रभावित नहीं करता है, तो क्या होता है जब कोई व्यक्ति आपके "UPSERT" रन से पहले रिकॉर्ड को हटा देता है? अब आप जिस रिकॉर्ड को अपडेट करने का प्रयास कर रहे हैं, वह मौजूद नहीं है, इसलिए वह इसके बजाय रिकॉर्ड बनाएगा। शायद वह व्यवहार नहीं है जिसकी आपको तलाश थी।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.