यदि आप काउंटर टेबल नहीं रखते हैं, तो दो विकल्प हैं। लेन-देन के भीतर, पहले MAX(seq_id)
. चुनें निम्न तालिका संकेतों में से एक के साथ:
WITH(TABLOCKX, HOLDLOCK)
WITH(ROWLOCK, XLOCK, HOLDLOCK)
TABLOCKX + HOLDLOCK
थोड़ा अधिक है। यह नियमित चुनिंदा बयानों को अवरुद्ध करता है, जिन्हें भारी . माना जा सकता है भले ही लेन-देन छोटा हो।
एक ROWLOCK, XLOCK, HOLDLOCK
तालिका संकेत शायद एक बेहतर विचार है (लेकिन:काउंटर टेबल के साथ विकल्प को आगे पढ़ें)। इसका लाभ यह है कि यह नियमित चयन कथनों को अवरुद्ध नहीं करता है, अर्थात जब चयन कथन SERIALIZABLE
में प्रकट नहीं होते हैं लेन-देन, या जब चयन कथन समान तालिका संकेत प्रदान नहीं करते हैं। ROWLOCK, XLOCK, HOLDLOCK
का उपयोग करना अभी भी इन्सर्ट स्टेटमेंट को ब्लॉक कर देगा।
निश्चित रूप से आपको यह सुनिश्चित करने की आवश्यकता है कि आपके प्रोग्राम का कोई अन्य भाग MAX(seq_id)
का चयन न करे इन तालिका संकेतों के बिना (या SERIALIZABLE
. के बाहर लेन-देन) और फिर पंक्तियों को सम्मिलित करने के लिए इस मान का उपयोग करें।
ध्यान दें कि इस तरह से लॉक की गई पंक्तियों की संख्या के आधार पर, यह संभव है कि SQL सर्वर लॉक को टेबल लॉक में बढ़ा देगा। लॉक एस्केलेशन के बारे में अधिक पढ़ें यहां ।
WITH(ROWLOCK, XLOCK, HOLDLOCK)
का उपयोग करते हुए डालने की प्रक्रिया इस प्रकार दिखेगा:
DECLARE @target_model INT=3;
DECLARE @part VARCHAR(128)='Spine';
BEGIN TRY
BEGIN TRANSACTION;
DECLARE @max_seq INT=(SELECT MAX(seq) FROM dbo.table_seq WITH(ROWLOCK,XLOCK,HOLDLOCK) WHERE [email protected]_model);
IF @max_seq IS NULL SET @max_seq=0;
INSERT INTO dbo.table_seq(part,seq,model)VALUES(@part,@max_seq+1,@target_model);
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH
काउंटर . रखना एक वैकल्पिक और शायद एक बेहतर विचार है तालिका, और ये तालिका संकेत काउंटर टेबल पर प्रदान करें। यह तालिका निम्न की तरह दिखेगी:
CREATE TABLE dbo.counter_seq(model INT PRIMARY KEY, seq_id INT);
फिर आप डालने की प्रक्रिया को इस प्रकार बदलेंगे:
DECLARE @target_model INT=3;
DECLARE @part VARCHAR(128)='Spine';
BEGIN TRY
BEGIN TRANSACTION;
DECLARE @new_seq INT=(SELECT seq FROM dbo.counter_seq WITH(ROWLOCK,XLOCK,HOLDLOCK) WHERE [email protected]_model);
IF @new_seq IS NULL
BEGIN SET @new_seq=1; INSERT INTO dbo.counter_seq(model,seq)VALUES(@target_model,@new_seq); END
ELSE
BEGIN SET @new_seq+=1; UPDATE dbo.counter_seq SET [email protected]_seq WHERE [email protected]_model; END
INSERT INTO dbo.table_seq(part,seq,model)VALUES(@part,@new_seq,@target_model);
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH
लाभ यह है कि कम पंक्ति ताले का उपयोग किया जाता है (अर्थात dbo.counter_seq
में प्रति मॉडल एक ), और लॉक एस्केलेशन पूरे dbo.table_seq
. को लॉक नहीं कर सकता तालिका इस प्रकार चुनिंदा बयानों को अवरुद्ध करती है।
WAITFOR DELAY '00:01:00'
डालकर आप इन सबका परीक्षण कर सकते हैं और स्वयं प्रभाव देख सकते हैं। counter_seq
. से अनुक्रम का चयन करने के बाद , और दूसरे SSMS टैब में तालिका (तालिकाओं) के साथ फ़िदा होना।
PS1:ROW_NUMBER() OVER (PARTITION BY model ORDER BY ID)
का उपयोग करना अच्छा तरीका नहीं है। यदि पंक्तियों को हटा दिया जाता है/जोड़ दिया जाता है, या आईडी बदल जाती है तो अनुक्रम बदल जाएगा (इनवॉइस आईडी पर विचार करें जो कभी नहीं बदलना चाहिए)। प्रदर्शन के मामले में भी एक पंक्ति को पुनर्प्राप्त करते समय पिछली सभी पंक्तियों की पंक्ति संख्या निर्धारित करना एक बुरा विचार है।
PS2:मैं लॉकिंग प्रदान करने के लिए बाहरी संसाधनों का कभी भी उपयोग नहीं करूंगा, जब SQL सर्वर पहले से ही आइसोलेशन स्तर या फाइन-ग्रेन्ड टेबल संकेतों के माध्यम से लॉकिंग प्रदान करता है।