-
आपको एक सेट में 10k पंक्तियों को तब तक अपडेट नहीं करना चाहिए जब तक कि आप सुनिश्चित न हों कि ऑपरेशन पेज लॉक हो रहा है (प्रति पृष्ठ कई पंक्तियों के कारण
UPDATE
का हिस्सा है। कार्यवाही)। मुद्दा यह है कि लॉक एस्केलेशन (पंक्ति या पेज से टेबल लॉक तक) 5000 लॉक पर होता है . इसलिए इसे 5000 के ठीक नीचे रखना सबसे सुरक्षित है, बस अगर ऑपरेशन रो लॉक्स का उपयोग कर रहा है। -
आपको नहीं करना चाहिए संशोधित की जाने वाली पंक्तियों की संख्या को सीमित करने के लिए SET ROWCOUNT का उपयोग करें। यहां दो मुद्दे हैं:
-
SQL सर्वर 2005 के रिलीज़ होने के बाद से इसे हटा दिया गया है (11 साल पहले):
<ब्लॉकक्वॉट>SQL सर्वर के भावी रिलीज़ में SET ROWCOUNT का उपयोग करने से DELETE, INSERT, और UPDATE स्टेटमेंट प्रभावित नहीं होंगे। नए विकास कार्य में DELETE, INSERT, और UPDATE स्टेटमेंट के साथ SET ROWCOUNT का उपयोग करने से बचें, और वर्तमान में इसका उपयोग करने वाले एप्लिकेशन को संशोधित करने की योजना बनाएं। समान व्यवहार के लिए, TOP सिंटैक्स का उपयोग करें
-
यह केवल उस कथन से अधिक प्रभावित कर सकता है जिसके साथ आप काम कर रहे हैं:
<ब्लॉकक्वॉट>SET ROWCOUNT विकल्प सेट करने से अधिकांश ट्रांजैक्ट-एसक्यूएल स्टेटमेंट्स की प्रोसेसिंग बंद हो जाती है, जब वे निर्दिष्ट संख्या में पंक्तियों से प्रभावित होते हैं। इसमें ट्रिगर शामिल हैं। ROWCOUNT विकल्प डायनेमिक कर्सर को प्रभावित नहीं करता है, लेकिन यह कीसेट और असंवेदनशील कर्सर की पंक्तियों को सीमित करता है। इस विकल्प का उपयोग सावधानी के साथ किया जाना चाहिए।
इसके बजाय,
TOP ()
. का उपयोग करें खंड। -
-
यहां स्पष्ट लेनदेन करने का कोई उद्देश्य नहीं है। यह कोड को जटिल बनाता है और आपके पास
ROLLBACK
. के लिए कोई प्रबंधन नहीं है , जिसकी आवश्यकता भी नहीं है क्योंकि प्रत्येक कथन का अपना लेन-देन होता है (अर्थात स्वतः-प्रतिबद्ध)। -
मान लें कि आपको स्पष्ट लेन-देन रखने का कोई कारण मिल गया है, तो आपके पास
TRY
नहीं है /CATCH
संरचना। कृपया मेरे उत्तर को DBA.StackExchange परTRY
. के लिए देखें /CATCH
टेम्प्लेट जो लेनदेन को संभालता है:क्या हमें C# कोड के साथ-साथ स्टोर प्रक्रिया में लेनदेन को संभालने की आवश्यकता है
मुझे संदेह है कि असली WHERE
प्रश्न में उदाहरण कोड में खंड नहीं दिखाया जा रहा है, इसलिए जो दिखाया गया है उस पर निर्भर करते हुए, एक बेहतर मॉडल होगा:
DECLARE @Rows INT,
@BatchSize INT; -- keep below 5000 to be safe
SET @BatchSize = 2000;
SET @Rows = @BatchSize; -- initialize just to enter the loop
BEGIN TRY
WHILE (@Rows = @BatchSize)
BEGIN
UPDATE TOP (@BatchSize) tab
SET tab.Value = 'abc1'
FROM TableName tab
WHERE tab.Parameter1 = 'abc'
AND tab.Parameter2 = 123
AND tab.Value <> 'abc1' COLLATE Latin1_General_100_BIN2;
-- Use a binary Collation (ending in _BIN2, not _BIN) to make sure
-- that you don't skip differences that compare the same due to
-- insensitivity of case, accent, etc, or linguistic equivalence.
SET @Rows = @@ROWCOUNT;
END;
END TRY
BEGIN CATCH
RAISERROR(stuff);
RETURN;
END CATCH;
@Rows
. का परीक्षण करके @BatchSize
. के विरुद्ध , आप उस अंतिम UPDATE
. से बच सकते हैं क्वेरी (ज्यादातर मामलों में) क्योंकि अंतिम सेट आमतौर पर @BatchSize
से कम पंक्तियों की कुछ संख्या होती है , इस मामले में हम जानते हैं कि प्रक्रिया करने के लिए और कुछ नहीं है (जो आप अपने उत्तर में दिखाए गए आउटपुट में देखते हैं)। केवल उन मामलों में जहां पंक्तियों का अंतिम सेट @BatchSize
. के बराबर है क्या यह कोड अंतिम UPDATE
चलाएगा 0 पंक्तियों को प्रभावित कर रहा है।
मैंने WHERE
. में एक शर्त भी जोड़ी है उन पंक्तियों को रोकने के लिए क्लॉज जिन्हें पहले ही अपडेट किया जा चुका है, उन्हें दोबारा अपडेट होने से रोका जा सकता है।
प्रदर्शन के बारे में नोट करें
मैंने ऊपर "बेहतर" पर जोर दिया (जैसा कि, "यह एक बेहतर . है मॉडल") क्योंकि इसमें ओपी के मूल कोड में कई सुधार हैं, और कई मामलों में ठीक काम करता है, लेकिन सभी मामलों के लिए सही नहीं है। कम से कम एक निश्चित आकार की तालिकाओं के लिए (जो कई कारकों के कारण भिन्न होता है इसलिए मैं कर सकता हूं' t अधिक विशिष्ट हो), प्रदर्शन ख़राब हो जाएगा क्योंकि ठीक करने के लिए कम पंक्तियाँ हैं यदि या तो:
- क्वेरी का समर्थन करने के लिए कोई अनुक्रमणिका नहीं है, या
- एक अनुक्रमणिका है, लेकिन
WHERE
. में कम से कम एक स्तंभ है क्लॉज एक स्ट्रिंग डेटा प्रकार है जो बाइनरी कॉलेशन का उपयोग नहीं करता है, इसलिए एकCOLLATE
बाइनरी कॉलेशन को बाध्य करने के लिए यहां क्वेरी में क्लॉज जोड़ा जाता है, और ऐसा करने से इंडेक्स (इस विशेष क्वेरी के लिए) अमान्य हो जाता है।
यह वह स्थिति है जिसका सामना @mikesigs ने किया, इस प्रकार एक अलग दृष्टिकोण की आवश्यकता है। अद्यतन विधि सभी पंक्तियों के लिए एक अस्थायी तालिका में अद्यतन करने के लिए आईडी की प्रतिलिपि बनाती है, फिर उस अस्थायी तालिका का उपयोग INNER JOIN
में करती है तालिका में संकुल अनुक्रमणिका कुंजी कॉलम पर अद्यतन किया जा रहा है। (संकुलित अनुक्रमणिका . पर कब्जा करना और उसमें शामिल होना महत्वपूर्ण है कॉलम, चाहे वे प्राथमिक कुंजी कॉलम हों!)।
विवरण के लिए कृपया नीचे @mikesigs उत्तर देखें। उस उत्तर में दिखाया गया दृष्टिकोण एक बहुत ही प्रभावी पैटर्न है जिसे मैंने कई अवसरों पर स्वयं उपयोग किया है। मैं केवल यही परिवर्तन करूंगा:
- स्पष्ट रूप से
#targetIds
बनाएंSELECT INTO...
. का उपयोग करने के बजाय तालिका #targetIds
के लिए तालिका, कॉलम पर क्लस्टर प्राथमिक कुंजी घोषित करें।#batchIds
के लिए तालिका, कॉलम पर क्लस्टर प्राथमिक कुंजी घोषित करें।#targetIds
में डालने के लिए ,INSERT INTO #targetIds (column_name(s)) SELECT
का उपयोग करें औरORDER BY
हटाएं क्योंकि यह अनावश्यक है।
इसलिए, यदि आपके पास कोई अनुक्रमणिका नहीं है जिसका उपयोग इस ऑपरेशन के लिए किया जा सकता है, और अस्थायी रूप से एक ऐसा नहीं बना सकता जो वास्तव में काम करेगा (एक फ़िल्टर किया गया अनुक्रमणिका आपके WHERE
के आधार पर काम कर सकती है। UPDATE
के लिए खंड query), फिर @mikesigs उत्तर में दिखाए गए दृष्टिकोण का प्रयास करें (और यदि आप उस समाधान का उपयोग करते हैं, तो कृपया इसे अप-वोट करें)।