[ भाग 1 | भाग 2 | भाग 3 | भाग 4 ]
इस श्रृंखला में अब तक, मैंने int
से अपसाइज़ करते समय पृष्ठ पर प्रत्यक्ष भौतिक प्रभाव का प्रदर्शन किया है। करने के लिए bigint
, और फिर इस ऑपरेशन के लिए कई सामान्य अवरोधकों के माध्यम से पुनरावृत्त किया गया। इस पोस्ट में, मैं दो संभावित समाधान की जांच करना चाहता था:एक सरल और एक अविश्वसनीय रूप से जटिल।
आसान तरीका
मेरी पिछली पोस्ट पर एक टिप्पणी में मुझे मेरी गड़गड़ाहट से थोड़ा सा लूट लिया गया था - कीथ मोनरो ने सुझाव दिया था कि आप तालिका को निचले नकारात्मक में संशोधित कर सकते हैं पूर्णांक डेटा प्रकार के लिए बाध्य, नए मानों के लिए आपकी क्षमता को दोगुना करना। आप इसे DBCC CHECKIDENT
के साथ कर सकते हैं :
DBCC CHECKIDENT(N'dbo.TableName', RESEED, -2147483648);
यह काम कर सकता है, यह मानते हुए कि सरोगेट मूल्यों का अंतिम उपयोगकर्ताओं के लिए कोई अर्थ नहीं है (या, यदि वे ऐसा करते हैं, तो उपयोगकर्ता अचानक नकारात्मक संख्या प्राप्त करके बाहर नहीं होंगे)। मुझे लगता है कि आप उन्हें बेवकूफ बना सकते हैं:
क्रिएट व्यू dbo.ViewNameAS सेलेक्ट आईडी =CONVERT(bigint, केस जब आईडी <0 तब (2147483648*2) - 1 + CONVERT(bigint, ID) ELSE ID END) dbo.TableName से;
इसका मतलब है कि जिस उपयोगकर्ता ने ID = -2147483648
. जोड़ा है वास्तव में +2147483648
see देखेंगे , वह उपयोगकर्ता जिसने ID = -2147483647
. जोड़ा देखेंगे +2147483649
, और इसी तरह। जब उपयोगकर्ता उस ID
से गुजरता है, तो रिवर्स गणना करना सुनिश्चित करने के लिए आपको अन्य कोड को समायोजित करना होगा। , उदा.
वैकल्पिक प्रक्रिया dbo.GetRowByID @ID bigintASBEGIN SET NOCOUNT ON; DECLARE @RealID bigint; SET @RealID =केस जब @ID> 2147483647 तब @ID - (2147483648*2) + 1 ELSE @ID END; आईडी चुनें, @ID /*, अन्य कॉलम */ dbo.TableName से जहां आईडी =@RealID;ENDGO
मैं इस आक्षेप का दीवाना नहीं हूं। बिल्कुल भी। यह गन्दा, भ्रामक और त्रुटि-प्रवण है। और यह सरोगेट कुंजियों में दृश्यता रखने को प्रोत्साहित करता है - आम तौर पर, IDENTITY
मूल्यों को अंतिम उपयोगकर्ताओं के सामने प्रकट नहीं किया जाना चाहिए, इसलिए उन्हें वास्तव में परवाह नहीं करनी चाहिए कि क्या वे ग्राहक 24, 642, -376, या शून्य के दोनों ओर बहुत बड़ी संख्या में हैं।
यह "समाधान" यह भी मानता है कि आपके पास कहीं भी ऐसा कोड नहीं है जो IDENTITY
द्वारा आदेशित हो कॉलम सबसे हाल ही में डाली गई पंक्तियों को पहले प्रस्तुत करने के लिए, या यह अनुमान लगाता है कि उच्चतम IDENTITY
मान नवीनतम पंक्ति होना चाहिए। कोड जो करता है IDENTITY
के क्रम पर भरोसा करें कॉलम, या तो स्पष्ट रूप से या परोक्ष रूप से (जो आपके विचार से अधिक हो सकता है यदि यह क्लस्टर इंडेक्स है), अब पंक्तियों को अपेक्षित क्रम में प्रस्तुत नहीं करेगा - यह RESEED
के बाद बनाई गई सभी पंक्तियों को दिखाएगा , पहले से शुरू करें, और फिर यह RESEED
. से पहले बनाई गई सभी पंक्तियों को दिखाएगा , पहले से शुरू।
इस दृष्टिकोण का प्राथमिक लाभ यह है कि इसके लिए आपको डेटा प्रकार बदलने की आवश्यकता नहीं होती है, और परिणामस्वरूप, RESEED
परिवर्तन के लिए अनुक्रमणिका, बाधाओं या इनबाउंड विदेशी कुंजियों में किसी परिवर्तन की आवश्यकता नहीं होती है।
नकारात्मक पक्ष - ऊपर उल्लिखित कोड परिवर्तनों के अलावा, निश्चित रूप से - यह है कि यह आपको केवल अल्पावधि में समय देता है। अंततः आप उपलब्ध सभी ऋणात्मक पूर्णांकों को भी समाप्त कर देंगे। और यह मत सोचो कि यह तालिका के वर्तमान संस्करण के उपयोगी जीवन को दोगुना कर देता है समय के संदर्भ में - कई मामलों में, डेटा वृद्धि तेज हो रही है, स्थिर नहीं रह रही है, इसलिए आप अगली 2 बिलियन पंक्तियों का उपयोग पहले 2 बिलियन की तुलना में बहुत तेज़ी से करेंगे।
एक कठिन रास्ता
एक और तरीका जो आप अपना सकते हैं वह है IDENTITY
. का उपयोग करना बंद करना स्तंभ पूरी तरह से; इसके बजाय आप SEQUENCE
. का उपयोग करके कनवर्ट कर सकते हैं . आप एक नया bigint
बना सकते हैं कॉलम, डिफ़ॉल्ट को SEQUENCE
. से अगले मान पर सेट करें , उन सभी मानों को मूल कॉलम के मानों के साथ अपडेट करें (यदि आवश्यक हो तो बैचों में), मूल कॉलम को छोड़ दें, और नए कॉलम का नाम बदलें। आइए इस काल्पनिक तालिका को बनाएं और एक पंक्ति डालें:
तालिका dbo.SequenceDemo(ID int IDENTITY(1,1), x char(1), CONSTRAINT PK_SD_Identity PRIMARY KEY CLUSTERED (ID)) बनाएं; GO INSERT dbo.SequenceDemo(x) VALUES('x');
इसके बाद, हम एक SEQUENCE
बनाएंगे जो एक इंट की ऊपरी सीमा के ठीक बाद शुरू होता है:
CREATE SEQUENCE dbo.BeyondIntAS bigint 2147483648 से शुरू करें 1 से वृद्धि;
अगला, SEQUENCE
. का उपयोग करने के लिए स्विच करने के लिए आवश्यक तालिका में परिवर्तन नए कॉलम के लिए:
लेनदेन शुरू करें; - एक नया "पहचान" कॉलम जोड़ें:वैकल्पिक तालिका dbo.SequenceDemo ID2 bigint जोड़ें; GO - मौजूदा पहचान मानों के बराबर नया कॉलम सेट करें-- बड़ी तालिकाओं के लिए, इसे बैचों में करने की आवश्यकता हो सकती है:अद्यतन dbo.SequenceDemo सेट आईडी2 =आईडी; - अब इसे अशक्त न बनाएं और हमारे SEQUENCE:ALTER TABLE dbo.SequenceDemo ALTER COLUMN ID2 bigint NOT NULL;ALTER TABLE dbo.SequenceDemo ADD CONSTRAINT DF_SD_Identity DEFAULT NEXT VALUE for dbo.BeyondInt for ID2; - मौजूदा पीके (और किसी भी इंडेक्स) को छोड़ने की जरूरत है:वैकल्पिक तालिका dbo.SequenceDemo DROP CONSTRAINT PK_SD_Identity; -- पुराने कॉलम को छोड़ें और नए का नाम बदलें:ALTER TABLE dbo.SequenceDemo DROP COLUMN ID;EXEC sys.sp_rename N'dbo.SequenceDemo.ID2', N'ID', 'COLUMN'; -- अब PK को बैक अप करें:ALTER TABLE dbo.SequenceDemo ADD CONSTRAINT PK_SD_Identity PRIMARY KEY CLUSTERED (ID); प्रतिबद्ध लेनदेन;
इस मामले में, अगला इंसर्ट निम्नलिखित परिणाम देगा (ध्यान दें कि SCOPE_IDENTITY()
अब मान्य मान नहीं लौटाता):
INSERT dbo.SequenceDemo(x) VALUES('y'); Select Si =SCOPE_IDENTITY (); चयन आईडी, x से dbo.SequenceDemo; /* परिणाम सी ---- नल आईडी x---------- -1 x2147483648 y */
यदि तालिका बड़ी है और आपको उपरोक्त एक-शॉट लेन-देन के बजाय बैचों में नया कॉलम अपडेट करने की आवश्यकता है, जैसा कि मैंने यहां वर्णित किया है - उपयोगकर्ताओं को इस बीच तालिका के साथ बातचीत करने की अनुमति देता है - आपको एक ट्रिगर की आवश्यकता होगी SEQUENCE
. को ओवरराइड करने के स्थान पर डाली गई किसी भी नई पंक्तियों के लिए मूल्य, ताकि वे किसी भी कॉलिंग कोड के आउटपुट से मेल खाते रहें। (यह भी मानता है कि कुछ अपडेट स्वीकार करना जारी रखने के लिए आपके पास अभी भी पूर्णांक श्रेणी में कुछ जगह है; अन्यथा, यदि आप पहले ही सीमा समाप्त कर चुके हैं, तो आपको कुछ डाउनटाइम लेना होगा - या अल्पावधि में ऊपर दिए गए आसान समाधान का उपयोग करना होगा ।)
आइए सब कुछ छोड़ दें और फिर से शुरू करें, फिर बस नया कॉलम जोड़ें:
DROP TABLE dbo.SequenceDemo;DROP SEQUENCE dbo.BeyondInt;GO CREATE TABLE dbo.SequenceDemo(ID int IDENTITY(1,1), x char(1), CONSTRAINT PK_SD_Identity PRIMARY KEY CLUSTERED (ID)); .SequenceDemo(x) VALUES('x');GO CREATE SEQUENCE dbo.BeyondIntAS bigint के साथ शुरू करें 2147483648 के साथ 1 से वृद्धि; तालिका dbo को बदल दें। अनुक्रम डेमो आईडी 2 बिगिंट जोड़ें; जाओ
और यहां वह ट्रिगर है जिसे हम जोड़ेंगे:
CREATE TRIGGER dbo.After_SequenceDemoON dbo.SequenceDemoAFTER INSERTASBEGIN UPDATE sd SET sd.ID2 =sd.ID फ्रॉम dbo.SequenceDemo AS sd INNER JOIN AS i ON sd.i.ID;
इस बार, अगली प्रविष्टि दोनों स्तंभों के लिए पूर्णांकों की निचली श्रेणी में पंक्तियाँ उत्पन्न करना जारी रखेगी, जब तक कि सभी पूर्व-मौजूदा मानों को अद्यतन नहीं किया जाता है और शेष परिवर्तन किए गए हैं:
INSERT dbo.SequenceDemo(x) VALUES('y'); Select Si =SCOPE_IDENTITY (); चयन आईडी, ID2, x से dbo.SequenceDemo; /* परिणाम सी-----2 आईडी आईडी2 x----------1 नल x2 2 y */
अब, हम मौजूदा ID2
. को अपडेट करना जारी रख सकते हैं मान जबकि नई पंक्तियाँ निचली सीमा में सम्मिलित होती रहती हैं:
नोकाउंट चालू करें; DECLARE @r INT =1; जबकि @r> 0BEGIN लेनदेन शुरू करें; अद्यतन शीर्ष (10000) dbo.SequenceDemo SET ID2 =ID जहां ID2 शून्य है; सेट @r =@@ ROWCOUNT; प्रतिबद्ध लेनदेन; - चेकपॉइंट; -- यदि सरल हो -- बैकअप लॉग ... -- यदि पूर्ण हो तोEND
एक बार जब हम सभी मौजूदा पंक्तियों को अपडेट कर लेते हैं, तो हम बाकी परिवर्तनों के साथ जारी रख सकते हैं, और फिर ट्रिगर छोड़ सकते हैं:
लेनदेन शुरू करें;वैकल्पिक तालिका dbo.अनुक्रम डेमो ALTER COLUMN ID2 BIGINT NOT NULL;ALTER TABLE dbo.SequenceDemo ADD CONSTRAINT DF_SD_Identity DEFAULT अगला मान dbo के लिए। DROP COLUMN ID;EXEC sys.sp_rename N'dbo.SequenceDemo.ID2', N'ID', 'COLUMN';ALTER TABLE dbo.SequenceDemo ADD CONSTRAINT PK_SD_Identity PRIMARY KEY CLUSTERED MITTRA (NS);DROP TRIGCOMCOM MITTRA_DBO; पूर्व>अब, अगला इंसर्ट इन मानों को उत्पन्न करेगा:
INSERT dbo.SequenceDemo(x) VALUES('z'); Select Si =SCOPE_IDENTITY (); चयन आईडी, x से dbo.SequenceDemo; /* परिणाम सी ---- नल आईडी x---------- -1 x2 y2147483648 z */अगर आपके पास कोड है जो
SCOPE_IDENTITY()
. पर निर्भर करता है ,@@IDENTITY
, याIDENT_CURRENT()
, इसे भी बदलना होगा, क्योंकि उन मानों को डालने के बाद अब पॉप्युलेट नहीं किया जाएगा - हालांकिOUTPUT
क्लॉज को अधिकांश परिदृश्यों में सही ढंग से काम करना जारी रखना चाहिए। यदि आपको यह विश्वास जारी रखने के लिए अपने कोड की आवश्यकता है कि तालिका एकIDENTITY
उत्पन्न करती है मूल्य, तो आप इसे नकली बनाने के लिए ट्रिगर का उपयोग कर सकते हैं - हालांकि यह केवल@@IDENTITY
को पॉप्युलेट करने में सक्षम होगा डालने पर, नहींSCOPE_IDENTITY()
. इसमें अभी भी बदलाव की आवश्यकता हो सकती है, क्योंकि ज्यादातर मामलों में, आप@@IDENTITY
पर भरोसा नहीं करना चाहते हैं किसी भी चीज़ के लिए (इसलिए, यदि आप परिवर्तन करने जा रहे हैं, तोIDENTITY
के बारे में सभी धारणाओं को हटा दें कॉलम बिल्कुल)।ट्रिगर बनाएं dbo.FakeIdentityON dbo.SequenceDemoINSERTASBEGIN SET NOCOUNT ON की जगह; DECLARE @lowestID bigint =(सम्मिलित से मिन (आईडी) चुनें); DECLARE @sql nvarchar(max) =N'DECLARE @foo TABLE(ID bigint Identity('+ CONVERT(varchar(32), @lowestID) + N',1));'; @sql +=N'INSERT @foo डिफ़ॉल्ट मान चुनें;' डाला से; EXEC sys.sp_executesql @sql; INSERT dbo.SequenceDemo(ID, x) सेलेक्ट आईडी, x से डाला गया;ENDअब, अगला इंसर्ट इन मानों को उत्पन्न करेगा:
INSERT dbo.SequenceDemo(x) VALUES('a'); Select Si =SCOPE_IDENTITY (), पहचान =@@ पहचान; चयन आईडी, x से dbo.SequenceDemo; /* परिणाम सी पहचान ---- ----- नल 2147483649 आईडी x---------- -1 x2 y2147483648 z2147483649 a */इस वर्कअराउंड के साथ, आपको अभी भी अन्य बाधाओं, इंडेक्स और इनबाउंड विदेशी कुंजियों के साथ तालिकाओं से निपटने की आवश्यकता होगी। स्थानीय बाधाएं और अनुक्रमणिका बहुत सीधी हैं, लेकिन मैं इस श्रृंखला के अगले भाग में विदेशी कुंजियों के साथ अधिक जटिल स्थिति से निपटूंगा।
एक जो काम नहीं करेगा, लेकिन मेरी इच्छा है कि यह होगा
ALTER TABLE SWITCH
कुछ मेटाडेटा परिवर्तन करने का एक बहुत शक्तिशाली तरीका हो सकता है जिसे अन्यथा पूरा करना मुश्किल है। और आम धारणा के विपरीत, इसमें केवल विभाजन शामिल नहीं है, और यह एंटरप्राइज़ संस्करण तक ही सीमित नहीं है। निम्नलिखित कोड एक्सप्रेस पर काम करेगा, और यह एक तरीका है जिसका उपयोग लोगों नेIDENTITY
को जोड़ने या हटाने के लिए किया है एक मेज पर संपत्ति (फिर से, विदेशी चाबियों और उन सभी अन्य अजीब अवरोधकों के लिए लेखांकन नहीं)।टेबल डीबीओ बनाएं। पहचान के साथ (आईडी int पहचान (1,1) न्यूल नहीं); टेबल डीबीओ बनाएं। बिना पहचान के (आईडी int न्यूल नहीं); वैकल्पिक तालिका डीबीओ।पहचान के साथ डीबीओ पर स्विच करें।पहचान के बिना;गो ड्रॉप टेबल डीबीओ।विदआइडेंटिटी;EXEC sys.sp_rename N'dbo.विदाउटआइडेंटिटी', N'dbo.withIdentity', 'OBJECT';यह काम करता है क्योंकि डेटा प्रकार और शून्यता बिल्कुल मेल खाते हैं, और
IDENTITY
पर कोई ध्यान नहीं दिया जाता है गुण। हालांकि, डेटा प्रकारों को मिलाने की कोशिश करें, और चीजें इतनी अच्छी तरह से काम नहीं करती हैं:टेबल डीबीओ बनाएं। सोर्सटेबल (आईडी int पहचान (1,1) न्यूल नहीं); टेबल डीबीओ बनाएं। ट्राईस्विच (आईडी बिगिंट पहचान (1,1) न्यूल नहीं); ALTER TABLE dbo.SourceTable स्विच टू dbo.TrySwitch;इसका परिणाम है:
Msg 4944, Level 16, State 1
ALTER TABLE SWITCH Statement विफल हो गया क्योंकि कॉलम 'ID' में सोर्स टेबल 'dbo.SourceTable' में डेटा टाइप int है, जो टारगेट टेबल 'dbo.TrySwitch' में इसके टाइप बिगिंट से अलग है।यह बहुत अच्छा होगा यदि एक
SWITCH
इस तरह के परिदृश्य में ऑपरेशन का उपयोग किया जा सकता है, जहां स्कीमा में एकमात्र अंतर वास्तव में समायोजित करने के लिए किसी भी भौतिक परिवर्तन की आवश्यकता नहीं थी (फिर से, जैसा कि मैंने भाग 1 में दिखाया था, डेटा नए पृष्ठों पर फिर से लिखा गया है, भले ही ऐसा करने की कोई आवश्यकता नहीं है)।निष्कर्ष
इस पोस्ट ने आपके मौजूदा
IDENTITY
. को बदलने से पहले या तो आपको समय देने के लिए दो संभावित समाधान की जांच की कॉलम, याIDENTITY
को छोड़ना पूरी तरह से अभीSEQUENCE
. के पक्ष में . यदि इनमें से कोई भी समाधान आपको स्वीकार्य नहीं है, तो कृपया भाग 4 देखें, जहां हम इस समस्या से सीधे तौर पर निपटेंगे।—
[ भाग 1 | भाग 2 | भाग 3 | भाग 4 ]