2010-02-17 14 views
8

मेरे पास SQL ​​सर्वर में एक एसपी है जो एक मिनट में सैकड़ों बार चलता है, और डेटाबेस के विरुद्ध आने वाले ट्रैफ़िक की जांच करने की आवश्यकता होती है। फिलहाल यहजो तेजी से है, INSERT से पहले या उसके बाद EXISTS?

INSERT INTO table 
SELECT @value1,@value2 WHERE NOT EXISTS 
(SELECT * FROM table WHERE value1 = @value1 AND value2 = @value2); 

हालांकि निम्नलिखित करता है, मैं भी

IF NOT EXISTS(SELECT * FROM table WHERE value1 = @value1 AND value2 = @value2)  
    INSERT INTO table (value1,value2) VALUES (@value1,@value2); 

कौन सा तेजी से किया जाएगा साथ जा सकते हैं? मुझे लगता है कि उनके बीच बहुत अंतर नहीं है लेकिन मैं ऐतिहासिक रूप से टीएसक्यूएल पर बहुत अच्छा नहीं हूं ... =/

अपडेट: हूप्स ... यह कहना है कि EXISTS 1 से अधिक मान का उपयोग करता है या नहीं रिकॉर्ड मौजूद है, इसलिए एक अनूठी बाधा काम नहीं करेगी। नमूना को प्रतिबिंबित करने के लिए संपादित किया गया है ...

+0

http://stackoverflow.com/questions/2276023/t-sql-insert-or-update –

+0

@carlos: यह वास्तव में एक अलग सवाल है, हालांकि कुछ हद तक संबंधित है। –

+1

आपका दूसरा विकल्प बस सुरक्षित नहीं है। 'IF' और' INSERT' कथन के बीच एक समवर्ती 'INSERT' हो सकता है। – Quassnoi

उत्तर

1

इस प्रश्न और उसके उत्तरों पर एक गजबियन टिप्पणियां जोड़ने के बाद, मुझे इसका उत्तर देने पर अपना स्वयं का जाना होगा।

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

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

चाहे विशिष्टता जांच स्पष्ट या निहित है, AFAIK से कोई फर्क नहीं पड़ता।यदि डीबीएमएस के पेट के अंदर "अंदर" चेक करके कुछ भी प्राप्त किया जाता है, तो यह लाभ केवल डुप्लिकेट मौजूद होने पर त्रुटियों को बढ़ाने और संभालने के साथ जुड़े ओवरहेड द्वारा खाया जा सकता है।


लब्बोलुआब यह है: एक सूचकांक मान लिया जाये कि पहले से ही जगह में, मेरी सिफारिश है कि आप अनुभवजन्य परीक्षण प्रदर्शन तीन सुझाव दिया समाधान पर है अगर आप अभी भी लगता है अपने आप को प्रदर्शन के लिए lusting। एक छोटे से प्रोग्राम को कुक करें जो अपेक्षित इनपुट डेटा को अनुकरण करता है, और तीन समाधानों में से प्रत्येक को हल करता है जिसमें कुछ अरब पंक्तियां होती हैं, जिनमें डुप्लिकेट की एक उचित मात्रा शामिल है। इस करते हैं, एक मुश्किल से समवर्ती माहौल में :-)

+0

धन्यवाद, वर्तमान में प्रत्येक कॉलम पर एक अनुक्रमणिका है लेकिन दोनों को कवर करने वाले एकाधिक कॉलम इंडेक्स नहीं हैं। मुझे लगता है कि मैं इसके साथ जाऊंगा और एक अनूठी बाधा डालूंगा। मुझे नहीं पता था कि मैं कई स्तंभों में फैली एक अनूठी बाधा जोड़ सकता हूं। – roryok

+0

@roryok: वास्तव में, आप केवल अपनी अनुक्रमणिका को 'अद्वितीय इंडेक्स' में बदल सकते हैं, यह वही होगा। – Quassnoi

+1

धन्यवाद दोस्तों! StackOverflow पर पहली बार पोस्टिंग और मुझे यह पसंद है! दौड़ की स्थिति के जोखिम का उल्लेख करने के लिए – roryok

0

यदि आप मूल्यों को अद्वितीय बनाना चाहते हैं, तो क्यों न केवल मूल्य पर एक अद्वितीय बाधा उत्पन्न करें, चयन के बिना एक INSERT करें और दृढ़ता से उल्लंघन उल्लंघन त्रुटि को संभालें?

यह इन दृष्टिकोणों में से किसी एक से तेज़ होगा।

इसके अलावा, आपका पहला दृष्टिकोण काम नहीं करता है - जब तक आप चयन करने के लिए चुनते हैं, तो आप पहले ही मूल्य डालते हैं, इसलिए चयन करें कि आपने जो अभी डाला है उसे स्पष्ट रूप से ढूंढें।

+2

मेरा मानना ​​है कि आप अपने पिछले अनुच्छेद में गलत हैं। 'WHERE' क्लॉज' SELECT' से जुड़ा हुआ है, जिसे वास्तव में डालने से पहले "पहले" निष्पादित किया जाता है। –

+0

अच्छी तरह से मुझे लगता है कि मैंने अपनी पहली स्टैक ओवरफ्लो गलती की, तो मैंने उन उदाहरणों को सरल बना दिया! यह वास्तव में दो मूल्यों के साथ रिकॉर्ड की जांच कर रहा है, इसलिए रिकॉर्ड अद्वितीय नहीं हैं ... मैं इसे प्रतिबिंबित करने के लिए इसे संपादित करूंगा। मैं पहली विधि की 100% गारंटी देता हूं, मैंने इसे कई बार परीक्षण किया है। – roryok

+2

एकाधिक स्तंभों में फैले 'अद्वितीय बाधा' को जोड़ना कोई समस्या नहीं होनी चाहिए। –

0

अगर मुझे लगता है, तो मुझे लगता है कि दूसरा विकल्प तेज़ होगा। यदि अस्तित्व विफल रहता है तो एसक्यूएल सर्वर को सम्मिलित करने के लिए किसी भी प्रकार का सेटअप नहीं करना पड़ेगा, जबकि पहले में, यह कुछ टेबल और फ़ील्ड नाम देख सकता है और ऐसा कोई भी डालने के लिए तैयार नहीं होता है जो कभी नहीं होता है। हालांकि, मैं इसे क्वेरी विश्लेषक में आज़माउंगा और देख सकता हूं कि योजना क्या कहती है।

+0

पर देखूंगा, दूसरी तरफ, पहला विकल्प एक बैच स्टेटमेंट है, जबकि दूसरा एक और प्रक्रियात्मक शैली में कई कथन है। एक आरडीबीएमएस आमतौर पर बैच स्टेटमेंट के साथ बहुत ही कुशल होता है, प्रक्रियात्मक/अनिवार्य कोड के साथ कम। उस ने कहा, मुझे नहीं पता कि हाथ में दो बयान कौन सा सर्वश्रेष्ठ प्रदर्शन करता है :) –

1

बस कर, और किसी भी त्रुटि को अनदेखा (पर मूल्य एक अद्वितीय बाधा मान लिया गया है) ...

BEGIN TRY 
    INSERT INTO Table (value) VALUES (@value); 
END TRY 
BEGIN CATCH 
    PRINT 'it was already in there!' 
END CATCH 

के बाद से इस बार के सैकड़ों एक मिनट चलाता है, लॉकिंग संकेत का चयन करता है में जोड़ा जाना चाहिए और avoid a race condition

(SELECT * FROM Table WITH (UPDLOCK, HOLDLOCK) WHERE value = @value); 

के एक सौदे तथापि, के अपने प्रस्तावित विचार सिर्फ डालें और किसी भी डुप्लिकेट बाधा त्रुटि को अनदेखा साथ ही एक रेस स्थिति से बच जाएंगे।

+0

धन्यवाद केएम, मैं इस समय चयन पर (NOLOCK) का उपयोग कर रहा हूं ... उसमें भी उल्लेख किया जाना चाहिए था! – roryok

+0

@roryok, यदि एक ही समय में इस एसक्यूएल में दो कॉल किए जाते हैं (आप कहते हैं कि यह एक मिनट में सैकड़ों बार चलाया जाता है) जिनके पास वही वैल्यू हैं जो वे संभवतः दोनों मौजूदा पंक्ति का चयन नहीं कर सकते हैं और दोनों को सम्मिलित करने का प्रयास करते हैं और इस प्रकार बनाते हैं डुप्लीकेट्स, अपने इरादों को हराकर –

+1

ध्यान दें कि अपवाद ट्रिगर के अंदर उठाए गए लेनदेन को खत्म कर देगा। – Quassnoi

3

अपने परिणामों को पोस्ट करने के लिए सुनिश्चित हो, एक समवर्ती INSERT अपने दूसरे प्रश्न में IF NOT EXISTS और INSERT के बीच में हो सकता है।

आपकी पहली क्वेरी साझा किए गए रिकॉर्ड पर साझा ताले रखेगी, जो क्वेरी के अंत तक नहीं उठाई जाएगी, इसलिए क्वेरी चलने तक एक नया रिकॉर्ड डालना असंभव होगा।

हालांकि, आपको इस व्यवहार पर पूरी तरह से भरोसा नहीं करना चाहिए। value पर एक अतिरिक्त UNIQUE बाधा रखें।

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

+2

+1। –

5

दोनों प्रकार गलत हैं। आप डुप्लिकेट @ वैल्यू 1, @ वैल्यू 2, की गारंटी की गारंटी देंगे।

ALTER TABLE Table ADD CONSTRAINT uniqueValue1Value UNIQUE (value1, values2); 

और डालने के लिए:

BEGIN TRY 
    INSERT INTO Table (value1, value2) VALUES (@value1, @value2); 
END TRY 
BEGIN CATCH 
    DECLARE @error_number int, @error_message NVARCHAR(4000), @xact_state INT; 
    SET @error_number = ERROR_NUMBER(); 
    SET @error_message = ERROR_MESSAGE(); 
    SET @xact_state = XACT_STATE(); 
    IF (@xact_state = -1) 
    BEGIN 
    ROLLBACK TRANSACTION; 
    END 
    IF (@error_number != 2627) /* 2627 is ' Cannot insert duplicate key in object ...' */ 
    BEGIN 
     RAISERROR(N'Error inserting into Table: %i %s', 16,1, @errror_number, @error_message); 
    END 
ENd CATCH 

जबकि

इस संभाल करने के लिए सही तरीका दो स्तंभों पर एक अद्वितीय बाधा लागू करने के लिए और हमेशा डालें और बाधा उल्लंघन को संभालने के लिए है ये जटिल लग सकते हैं, किसी को शुद्धता नामक थोड़ी सी जानकारी में कारक होना चाहिए। लॉक संकेत आधारित समाधान के साथ तुलना में यह बहुत आसान है। यह भी सबसे अधिक प्रदर्शन करने वाला समाधान है: केवल एक ही खोज करता है। अन्य सभी समाधानों को कम से कम दो खोजों की आवश्यकता होती है (एक यह सत्यापित करने के लिए कि इसे सम्मिलित किया जा सकता है, एक डालने के लिए)।

+0

धन्यवाद रीमस। रोलबैक ट्रांज़ेक्शन किस लेनदेन को प्रभावित करेगा? संपूर्ण एसपी एक लेनदेन वक्तव्य में संलग्न है जिसमें इनमें से कुछ और सम्मिलित बयान शामिल हैं, यदि मूल्य पहले से मौजूद है तो मैं पूरी चीज़ को समाप्त नहीं करना चाहता हूं ... – roryok

+1

जब XACT_STATE() -1 है तो आपके पास कोई विकल्प नहीं है , इसका मतलब है कि ट्रांसकेशन बर्बाद हो गया है और यह * रोलबैक होना चाहिए। एक अनूठा बाधा उल्लंघन रोलबैक का कारण नहीं बनता है, यह तब होगा जब एक और गंभीर त्रुटि आई है, उदाहरण के लिए डिस्क स्पेस से रननिग। –

+0

चर्चा में केवल 3 साल देर हो चुकी थी लेकिन मैं आपके बयान के बारे में सोच रहा था कि डुप्लीकेट की गारंटी है: INSERT ... कैसे नहीं है() डुप्लीकेट का कारण बन सकता है? चूंकि INSERT और SELECT दोनों एक ही लेन-देन में हैं, बाद में रिकॉर्ड रिकॉर्ड पर लॉक लेते हैं और इसे जारी नहीं करते हैं जब तक कि INSERT समाप्त नहीं हो जाता है। यह अन्य कनेक्शन को एक ही आईएनएसईआरटी बनाने से रोकता है क्योंकि डालने के बाद तक उन्हें लॉक नहीं मिल सकता है। मैं वर्षों से ऐसा कर रहा हूं और इसके साथ कभी भी कोई समस्या नहीं थी। AFAIK यह एकाधिक-रिकॉर्ड प्रविष्टियों के दौरान उपयोग करने का एकमात्र वैध दृष्टिकोण भी है। – deroby

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