11

मैं एक यूपीएसईआरटी का चयन/INSERT संस्करण करना चाहता हूं। नीचे मौजूदा कोड का एक टेम्पलेट है:उपरोक्त के संस्करण का चयन/सम्मिलित करें: क्या उच्च समवर्तीता के लिए एक डिज़ाइन पैटर्न है?

// CREATE TABLE Table (RowID INT NOT NULL IDENTITY(1,1), RowValue VARCHAR(50)) 

IF NOT EXISTS (SELECT * FROM Table WHERE RowValue = @VALUE) 
BEGIN 
    INSERT Table VALUES (@Value) 
    SELECT @id = SCOPEIDENTITY() 
END 
ELSE 
    SELECT @id = RowID FROM Table WHERE RowValue = @VALUE) 

क्वेरी कई समवर्ती सत्रों से बुलाया जाएगा। मेरे प्रदर्शन परीक्षण से पता चलता है कि यह लगातार एक विशिष्ट लोड के तहत प्राथमिक कुंजी उल्लंघनों को फेंक देगा।

क्या इस क्वेरी के लिए एक उच्च-समवर्ती विधि है जो इसे पहले से मौजूद डेटा के सम्मिलन से परहेज करते हुए प्रदर्शन को बनाए रखने की अनुमति देगी?

+1

यह इसी प्रकार है: http://stackoverflow.com/questions/13540/insert-update-stored-proc-on-sql-server/193876#193876 –

+0

मैं सहमत हूं कि यह समान है, लेकिन मैं कहूंगा कि अंतर है कि अद्यतन की कोई आवश्यकता नहीं है, बस एक डालने या चयन कथन।आपके उत्तर में, आप संयुक्त संकेत के रूप में सर्जिकलबल का उपयोग करते हैं। क्या यह उपरोक्त क्वेरी पर उपरोक्त क्वेरी के लिए आपकी सिफारिश होगी? – 8kb

+0

सीरियलज़ेबल संकेत के साथ एक सम्मिलित करें, संभावित रूप से लेनदेन में चाल चलनी चाहिए। मैं एक उत्तर लिखने की कोशिश कर सकता हूं लेकिन यह आईपैड मुझे ध्वनि ब्रश बनाता है :( –

उत्तर

15

आप चीजों को सरल बनाने के लिए LOCK का उपयोग कर सकते हैं लेकिन यह समरूपता को कम करता है। "सामान्य उपचार" की सुरक्षित संचालन के बाद पहले सामान्य स्थिति को क्यों न करें ("ज्यादातर डालें या अधिकतर चुनें")? यही कारण है कि, "JFDI" पैटर्न ... है

अधिकतर आवेषण (गेंद पार्क 70-80% +) की उम्मीद:

बस सम्मिलित करने के लिए प्रयास करें। यदि यह विफल रहता है, तो पंक्ति पहले से ही बनाई जा चुकी है। समवर्तीता के बारे में चिंता करने की आवश्यकता नहीं है क्योंकि TRY/CATCH आपके लिए डुप्लीकेट से संबंधित है।

BEGIN TRY 
    INSERT Table VALUES (@Value) 
    SELECT @id = SCOPEIDENTITY() 
END TRY 
BEGIN CATCH 
    IF ERROR_NUMBER() <> 2627 
     RAISERROR etc 
    ELSE -- only error was a dupe insert so must already have a row to select 
     SELECT @id = RowID FROM Table WHERE RowValue = @VALUE 
END CATCH 

अधिकतर का चयन करता है:

इसी प्रकार, लेकिन पहले डेटा प्राप्त करने की कोशिश। कोई डेटा = INSERT की आवश्यकता नहीं है। दोबारा, यदि 2 समवर्ती कॉल INSERT को आज़माएं क्योंकि वे दोनों को TRY/CATCH हैंडल गायब होने वाली पंक्ति मिली।

BEGIN TRY 
    SELECT @id = RowID FROM Table WHERE RowValue = @VALUE 
    IF @@ROWCOUNT = 0 
    BEGIN 
     INSERT Table VALUES (@Value) 
     SELECT @id = SCOPEIDENTITY() 
    END 
END TRY 
BEGIN CATCH 
    IF ERROR_NUMBER() <> 2627 
     RAISERROR etc 
    ELSE 
     SELECT @id = RowID FROM Table WHERE RowValue = @VALUE 
END CATCH 

दूसरा वाला खुद को दोहराने लगता है, लेकिन यह अत्यधिक समवर्ती है। ताले ही लेकिन संगामिति की कीमत पर प्राप्त होगा ...

संपादित करें:

क्यों मर्ज का उपयोग नहीं ...

आप आउटपुट खंड यह केवल वापस आ जाएगी का उपयोग करते हैं क्या अपडेट किया गया है। तो आपको OUTPUT क्लॉज के लिए अंतर्निहित तालिका उत्पन्न करने के लिए एक डमी अद्यतन की आवश्यकता है। यदि आपको कई कॉल (जैसे ओपी द्वारा निहित) के साथ डमी अपडेट करना है, तो बहुत सारे लॉग मेरिज का उपयोग करने में सक्षम होने के लिए लिखते हैं।

+0

@ जीबीएन - आप MERGE कमांड के बजाय अपने दूसरे सुझाव (उच्च सहमति के लिए) का उपयोग क्यों करेंगे (मानते हैं कि @ 8 केबी एसक्यूएल 20 का उपयोग कर रहा है 08+)? –

+0

@ शुद्ध। क्रोम: क्योंकि यह सम्मिलित/चयन है, सम्मिलित/अद्यतन नहीं है। आप आउटपुट का उपयोग करने के लिए एक डमी अद्यतन के साथ समाप्त हो जाएगा। महान। – gbn

+0

@ जीबीएन - इसलिए हम डाला गया _last_/_ हालिया हालिया_ पहचान को पकड़ने के लिए SCOPE_IDENTITY की जांच नहीं कर सकते .. एक सम्मिलित हुआ मान लिया? अगर ऐसा नहीं होता है, तो आप यह जांचने के लिए @@ रोकाउंट का उपयोग कर सकते हैं कि अपडेट काम करता है ... ?? –

1
// CREATE TABLE Table (RowID INT NOT NULL IDENTITY(1,1), RowValue VARCHAR(50)) 

- अपने क्लस्टर सूचकांक के रूप में RowValue और RowID पर एक गैर क्लस्टर अद्वितीय सूचकांक है सुनिश्चित करें।

IF EXISTS (SELECT * FROM Table WHERE RowValue = @VALUE) 
    SELECT @id = RowID FROM Table WHERE RowValue = @VALUE 
ELSE BEGIN 
    INSERT Table VALUES (@Value) 
    SELECT @id = SCOPEIDENTITY() 
END 
0

हमेशा के रूप में, जीबीएन का जवाब सही है और आखिरकार मुझे उस स्थान पर ले जाता है जहां मुझे होना चाहिए। हालांकि, मुझे एक विशेष एज केस मिला जो उसके दृष्टिकोण से ढंका नहीं था। यह 2601 त्रुटि है जो Unique Index Violation की पहचान करता है।

इस के लिए क्षतिपूर्ति करने के लिए, मैं अपने कोड को संशोधित किया गया है का पालन करें

... 
declare @errornumber int = ERROR_NUMBER() 
if @errornumber <> 2627 and @errornumber <> 2601 
... 

के रूप में उम्मीद है कि इस में किसी को मदद करता है!

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