कम आम गतिरोधों में से एक वह है जहां एक एकल उपयोगकर्ता होता है और वे कुछ सिस्टम संसाधनों पर खुद को गतिरोध करते हैं। हाल ही में एक मैं आया था एक उपनाम प्रकार बना रहा है, फिर उसी लेनदेन के अंदर उस प्रकार का एक चर घोषित कर रहा है। कल्पना कीजिए कि आप एक इकाई परीक्षण या पूर्व-तैनाती परीक्षण चलाने की कोशिश कर रहे हैं, विफलताओं की जांच कर रहे हैं, और किसी भी मामले में रोलबैक कर रहे हैं ताकि आपने जो किया है उसका कोई निशान न छोड़े। पैटर्न इस तरह दिख सकता है:
BEGIN TRANSACTION; GO CREATE TYPE EmailAddress FROM VARCHAR(320); GO DECLARE @x TABLE (e EmailAddress); GO ROLLBACK TRANSACTION;
या, अधिक संभावना है, थोड़ा अधिक जटिल:
BEGIN TRANSACTION; GO CREATE TYPE EmailAddress FROM VARCHAR(320); GO CREATE PROCEDURE dbo.foo @param EmailAddress AS BEGIN SET NOCOUNT ON; DECLARE @x TABLE (e EmailAddress); INSERT @x SELECT @param; END GO DECLARE @x EmailAddress; SET @x = N'whatever'; EXEC dbo.foo @param = N'whatever'; GO ROLLBACK TRANSACTION;
मैंने पहली बार इस कोड को आजमाया था SQL सर्वर 2012, और दोनों उदाहरण निम्न त्रुटि के साथ विफल रहे:
Msg 1205, Level 13, State 55, Line 14लेन-देन (प्रक्रिया आईडी 57) एक अन्य प्रक्रिया के साथ लॉक संसाधनों पर गतिरोध था और उसे गतिरोध पीड़ित के रूप में चुना गया है। लेनदेन को फिर से चलाएँ।
और गतिरोध ग्राफ से सीखने के लिए बहुत कुछ नहीं है:
कुछ साल पीछे चलते हुए, मुझे याद है जब मैंने पहली बार उपनाम प्रकारों के बारे में सीखा था, वापस SQL Server 2000 में (जब उन्हें उपयोगकर्ता-परिभाषित डेटा प्रकार कहा जाता था)। उस समय, यह गतिरोध जो मैंने हाल ही में देखा था, वह नहीं होगा (लेकिन यह कम से कम आंशिक रूप से है क्योंकि आप एक अन्य प्रकार के साथ तालिका चर घोषित नहीं कर सकते - यहां और यहां देखें)। मैंने SQL Server 2000 RTM (8.0.194) और SQL Server 2000 SP4 (8.0.2039) पर निम्न कोड चलाया, और यह ठीक चला:
BEGIN TRANSACTION; GO EXEC sp_addtype @typename = N'EmailAddress', @phystype = N'VARCHAR(320)'; GO CREATE PROCEDURE dbo.foo @param EmailAddress AS BEGIN SET NOCOUNT ON; SELECT @param; END GO EXEC dbo.foo @param = N'whatever'; GO DECLARE @x EmailAddress; SET @x = N'whatever'; EXEC dbo.foo @param = @x; GO ROLLBACK TRANSACTION;
बेशक, यह परिदृश्य उस समय बहुत व्यापक नहीं था क्योंकि, आखिरकार, बहुत से लोगों ने उपनाम प्रकारों का इस्तेमाल पहले स्थान पर नहीं किया था। हालांकि वे आपके मेटाडेटा को अधिक स्व-दस्तावेजीकरण और डेटा-परिभाषा-जैसा बना सकते हैं, यदि आप उन्हें कभी भी बदलना चाहते हैं, तो वे एक शाही दर्द हैं, जो किसी अन्य पोस्ट के लिए एक विषय हो सकता है।
SQL सर्वर 2005 आया, और उपनाम प्रकार बनाने के लिए नया DDL सिंटैक्स पेश किया:CREATE TYPE
. इसने वास्तव में प्रकार बदलने के साथ समस्या का समाधान नहीं किया, इसने सिंटैक्स को थोड़ा साफ कर दिया। RTM में, उपरोक्त सभी कोड नमूनों ने बिना किसी गतिरोध के ठीक काम किया। SP4 में, हालांकि, वे सभी गतिरोध करेंगे। इसलिए, कहीं न कहीं RTM और SP4 के बीच, उन्होंने लेन-देन के लिए आंतरिक हैंडलिंग को बदल दिया जिसमें अन्य प्रकार के उपयोग से तालिका चर शामिल थे।
SQL सर्वर 2008 के लिए कुछ वर्षों को फास्ट फॉरवर्ड करें, जहां तालिका-मूल्यवान पैरामीटर जोड़े गए थे (यहां एक अच्छा उपयोग केस देखें)। इसने इन प्रकारों के उपयोग को और अधिक प्रचलित बना दिया, और एक और मामला पेश किया जहां एक लेन-देन जो इस तरह के प्रकार को बनाने और उपयोग करने का प्रयास करता है, गतिरोध होगा:
BEGIN TRANSACTION; GO CREATE TYPE dbo.Items AS TABLE(Item INT); GO DECLARE @r dbo.Items; GO ROLLBACK TRANSACTION;
मैंने कनेक्ट की जाँच की, और कई संबंधित आइटम पाए, उनमें से एक ने दावा किया कि यह समस्या SQL Server 2008 SP2 और 2008 R2 SP1 में ठीक कर दी गई है:
कनेक्ट #365876 :उपयोगकर्ता द्वारा परिभाषित डेटा प्रकार और इसका उपयोग करने वाली वस्तुओं को बनाते समय गतिरोध उत्पन्न होता है
इसे वास्तव में निम्नलिखित परिदृश्य के रूप में संदर्भित किया गया था, जहां केवल एक संग्रहीत कार्यविधि बनाना जो तालिका चर में प्रकार को संदर्भित करता है, SQL Server 2008 RTM (10.0.1600) और SQL Server 2008 R2 RTM (10.50.1600) में गतिरोध होगा:पी>
BEGIN TRANSACTION; GO CREATE TYPE EmailAddress FROM VARCHAR(320); GO CREATE PROCEDURE dbo.foo @param EmailAddress AS BEGIN SET NOCOUNT ON; DECLARE @x TABLE (e EmailAddress); INSERT @x SELECT @param; END GO ROLLBACK TRANSACTION;
हालाँकि, यह SQL Server 2008 SP3 (10.0.5846) या 2008 R2 SP2 (10.50.4295) में गतिरोध नहीं करता है। इसलिए मैं कनेक्ट आइटम पर टिप्पणियों पर विश्वास करता हूं - कि बग का यह हिस्सा 2008 SP2 और 2008 R2 SP1 में तय किया गया था, और अधिक आधुनिक संस्करणों में कभी भी कोई समस्या नहीं रही है।
लेकिन यह अभी भी किसी भी प्रकार के सच्चे परीक्षण के माध्यम से उपनाम प्रकार को वास्तव में रखने की क्षमता को छोड़ देता है। इसलिए मेरे यूनिट परीक्षण तब तक सफल होंगे जब तक मैं केवल यह परीक्षण करना चाहता था कि मैं प्रक्रिया बना सकता हूं - प्रकार को स्थानीय चर के रूप में या स्थानीय तालिका चर में कॉलम के रूप में घोषित करने के बारे में भूल जाओ।
इसे हल करने का एकमात्र तरीका लेन-देन शुरू करने से पहले तालिका प्रकार बनाना है, और बाद में इसे स्पष्ट रूप से छोड़ दें (या अन्यथा इसे कई लेनदेन में तोड़ दें)। यह बेहद बोझिल या असंभव भी हो सकता है, अक्सर स्वचालित परीक्षण ढांचे और हार्नेस इस सीमा के लिए उनके काम करने के तरीके को पूरी तरह से बदल देते हैं।
इसलिए मैंने सभी प्रमुख संस्करणों के शुरुआती और सबसे हाल के बिल्ड में कुछ परीक्षणों से गुजरने का फैसला किया:SQL सर्वर 2005 RTM, 2005 SP4, 2008 RTM, 2008 SP3, 2008 R2 RTM, 2008 R2 SP2, 2012 RTM, 2012 SP1, और 2014 CTP2 (और हाँ, मैंने उन सभी को स्थापित किया है)। मैंने कई कनेक्ट आइटम और विभिन्न टिप्पणियों की समीक्षा की थी जिसने मुझे आश्चर्यचकित कर दिया था कि कौन से उपयोग के मामलों का समर्थन किया गया था और कहां, और मुझे यह पता लगाने के लिए एक अजीब मजबूरी थी कि इस मुद्दे के कौन से पहलू वास्तव में तय किए गए थे। मैंने विभिन्न संभावित गतिरोध परिदृश्यों का परीक्षण किया जिसमें इन सभी बिल्डों के विरुद्ध उपनाम प्रकार, तालिका चर और तालिका-मूल्यवान पैरामीटर शामिल हैं; कोड इस प्रकार है:
/* alias type - declare in local table variable always deadlocks on 2005 SP4 -> 2014, except in 2005 RTM */ BEGIN TRANSACTION; GO CREATE TYPE EmailAddress FROM VARCHAR(320) GO DECLARE @r TABLE(e EmailAddress); GO ROLLBACK TRANSACTION; /* alias type - create procedure with param & table var sometimes deadlocks - 2005 SP4, 2008 RTM & SP1, 2008 R2 RTM */ BEGIN TRANSACTION; GO CREATE TYPE EmailAddress FROM VARCHAR(320); GO CREATE PROCEDURE dbo.foo @param EmailAddress AS BEGIN SET NOCOUNT ON; DECLARE @x TABLE (e EmailAddress); INSERT @x SELECT @param; END GO ROLLBACK TRANSACTION; /* alias type - create procedure, declare & exec always deadlocks on 2005 SP4 -> 2014, except on 2005 RTM */ BEGIN TRANSACTION; GO CREATE TYPE EmailAddress FROM VARCHAR(320); GO CREATE PROCEDURE dbo.foo @param EmailAddress AS BEGIN SET NOCOUNT ON; DECLARE @x TABLE (e EmailAddress); INSERT @x SELECT @param; END GO DECLARE @x EmailAddress; SET @x = N'whatever'; EXEC dbo.foo @param = N'whatever'; GO ROLLBACK TRANSACTION; /* obviously did not run these on SQL Server 2005 builds */ /* table type - create & declare local variable always deadlocks on 2008 -> 2014 */ BEGIN TRANSACTION; GO CREATE TYPE dbo.Items AS TABLE(Item INT); GO DECLARE @r dbo.Items; GO ROLLBACK TRANSACTION; /* table type - create procedure with param and SELECT never deadlocks on 2008 -> 2014 */ BEGIN TRANSACTION; GO CREATE TYPE dbo.Items AS TABLE(Item INT); GO CREATE PROCEDURE dbo.foo @param dbo.Items READONLY AS BEGIN SET NOCOUNT ON; SELECT Item FROM @param; END GO ROLLBACK TRANSACTION; /* table type - create procedure, declare & exec always deadlocks on 2008 -> 2014 */ BEGIN TRANSACTION; GO CREATE TYPE dbo.Items AS TABLE(Item INT); GO CREATE PROCEDURE dbo.foo @param dbo.Items READONLY AS BEGIN SET NOCOUNT ON; SELECT Item FROM @param; END GO DECLARE @x dbo.Items; EXEC dbo.foo @param = @x; GO ROLLBACK TRANSACTION;
और परिणाम ऊपर मेरी कहानी को दर्शाते हैं:SQL सर्वर 2005 RTM किसी भी परिदृश्य पर गतिरोध नहीं करता था, लेकिन जब तक SP4 चारों ओर लुढ़कता, तब तक वे सभी गतिरोध में थे। इसे 2008 SP2 और 2008 R2 SP1 में "एक प्रकार बनाएं और एक प्रक्रिया बनाएं" परिदृश्य के लिए ठीक किया गया था, लेकिन अन्य में से कोई भी नहीं। यहां सभी परिणाम दिखाने वाली एक तालिका है:
SQL सर्वर संस्करण / बिल्ड # | ||||||||||
एसक्यूएल 2005 | एसक्यूएल 2008 | SQL 2008 R2 | एसक्यूएल 2012 | एसक्यूएल 2014 | ||||||
RTM 9.0.1399 | SP4 9.0.5324 | RTM 10.0.1600 | SP3 10.0.5846 | RTM 10.50.1600 | SP2 10.50.4295 | RTM 11.0.2100 | SP1 11.0.3381 | CTP2 12.0.1524 | ||
तालिका var में घोषित करें | <टीडी वर्ग ="सेन जीबीजी">||||||||||
प्रक्रिया बनाएं | <टीडी वर्ग ="सेन जीबीजी"><टीडी वर्ग ="सेन जीबीजी"> | <टीडी वर्ग ="सेन जीबीजी"> <टीडी वर्ग ="सेन जीबीजी"> <टीडी वर्ग ="सेन जीबीजी"> <टीडी वर्ग ="सेन जीबीजी"> | ||||||||
खरीदारी बनाएं और निष्पादित करें | <टीडी वर्ग ="सेन जीबीजी">||||||||||
स्थानीय संस्करण घोषित करें | N/A | |||||||||
प्रक्रिया बनाएं | <टीडी वर्ग ="सेन जीबीजी"> <टीडी वर्ग ="सेन जीबीजी"> <टीडी वर्ग ="सेन जीबीजी"> <टीडी वर्ग ="सेन जीबीजी"> <टीडी वर्ग ="सेन जीबीजी"> <टीडी वर्ग ="सेन जीबीजी"> <टीडी वर्ग ="सेन जीबीजी">||||||||||
खरीदारी बनाएं और निष्पादित करें |
निष्कर्ष
तो, कहानी का नैतिक है, ऊपर वर्णित उपयोग के मामले के लिए अभी भी कोई फिक्स नहीं है, जहां आप एक टेबल प्रकार बनाना चाहते हैं, एक प्रक्रिया या फ़ंक्शन बनाएं जो प्रकार का उपयोग करता है, एक प्रकार घोषित करता है, मॉड्यूल का परीक्षण करता है, और रोल करता है सब कुछ वापस। किसी भी स्थिति में, आपके लिए देखने के लिए यहां अन्य कनेक्ट आइटम हैं; उम्मीद है कि आप उन्हें वोट कर सकते हैं और यह बताते हुए टिप्पणी छोड़ सकते हैं कि यह गतिरोध परिदृश्य आपके व्यवसाय को सीधे कैसे प्रभावित करता है:
मुझे उम्मीद है कि निकट भविष्य में इन कनेक्ट आइटम में कुछ स्पष्टीकरण जोड़े जाएंगे, हालांकि मुझे नहीं पता कि उन्हें कब आगे बढ़ाया जाएगा।