ALTER TABLE ... ALTER COLUMN
आदेश बहुत शक्तिशाली है। आप इसका उपयोग किसी कॉलम के डेटा प्रकार, लंबाई, सटीकता, स्केल, अशक्तता, मिलान ... और इसके अलावा कई अन्य चीजों को बदलने के लिए कर सकते हैं।
यह विकल्प की तुलना में निश्चित रूप से अधिक सुविधाजनक है:एक नई तालिका बनाना और हर बार परिवर्तन आवश्यक होने पर डेटा को स्थानांतरित करना। फिर भी, अंतर्निहित जटिलता को छिपाने के लिए केवल इतना ही किया जा सकता है। इस आदेश के साथ क्या संभव है, इस पर बड़ी संख्या में प्रतिबंधों के साथ, हमेशा प्रदर्शन का सवाल होता है।
अंततः, तालिकाओं को सिस्टम में कुछ मेटाडेटा के साथ बाइट्स के अनुक्रम के रूप में संग्रहीत किया जाता है ताकि यह वर्णन किया जा सके कि उनमें से प्रत्येक बाइट्स का क्या अर्थ है, और वे तालिका के विभिन्न स्तंभों में से प्रत्येक से कैसे संबंधित हैं। जब हम SQL सर्वर से कॉलम की परिभाषा के कुछ पहलू को बदलने के लिए कहते हैं, तो उसे यह जांचना होगा कि मौजूदा डेटा नई परिभाषा के अनुकूल है या नहीं। इसे यह भी निर्धारित करने की आवश्यकता है कि क्या वर्तमान भौतिक लेआउट को बदलने की आवश्यकता है।
परिवर्तन के प्रकार और डेटाबेस के कॉन्फ़िगरेशन के आधार पर, एक ALTER COLUMN
कमांड को निम्न में से कोई एक क्रिया करने की आवश्यकता होगी:
- केवल सिस्टम तालिकाओं में मेटाडेटा बदलें।
- संगतता के लिए सभी मौजूदा डेटा की जांच करें, फिर मेटाडेटा बदलें।
- नई परिभाषा से मेल खाने के लिए कुछ या सभी संग्रहीत डेटा को फिर से लिखें।
विकल्प 1 प्रदर्शन के दृष्टिकोण से आदर्श स्थिति का प्रतिनिधित्व करता है। इसके लिए सिस्टम टेबल में केवल कुछ बदलाव और लॉगिंग की न्यूनतम मात्रा की आवश्यकता होती है। ऑपरेशन के लिए अभी भी एक प्रतिबंधात्मक स्कीमा संशोधन की आवश्यकता होगी Sch-M
लॉक करें, लेकिन मेटाडेटा परिवर्तन स्वयं तालिका के आकार की परवाह किए बिना बहुत जल्दी पूरा हो जाएगा।
मेटाडेटा-केवल परिवर्तन
देखने के लिए कई विशेष मामले हैं, लेकिन एक सामान्य सारांश के रूप में, निम्नलिखित क्रियाओं के लिए केवल मेटाडेटा में परिवर्तन की आवश्यकता होती है:
NOT NULL
से जा रहे हैं करने के लिएNULL
समान डेटा प्रकार के लिए।varchar
का अधिकतम आकार बढ़ाना ,nvarchar
, याvarbinary
कॉलम (max
को छोड़कर) )।
एसक्यूएल सर्वर 2016 में सुधार
इस पोस्ट का विषय अतिरिक्त परिवर्तन है जो केवल मेटाडेटा के लिए सक्षम हैं SQL Server 2016 से आगे . सिंटैक्स में किसी बदलाव की आवश्यकता नहीं है, और किसी कॉन्फ़िगरेशन सेटिंग्स को संशोधित करने की आवश्यकता नहीं है। आपको ये गैर-दस्तावेज सुधार मुफ्त में मिलते हैं।
नई क्षमताएं निश्चित-लंबाई . के सबसेट को लक्षित करती हैं डेटा के प्रकार। निम्नलिखित परिस्थितियों में नई क्षमताएं पंक्ति-भंडार तालिकाओं पर लागू होती हैं:
- संपीड़न सक्षम होना चाहिए:
- सभी अनुक्रमणिका और विभाजन पर , बेस हीप या क्लस्टर्ड इंडेक्स सहित।
- या तो
ROW
याPAGE
संपीड़न। - अनुक्रमणिका और विभाजन मिश्रण . का उपयोग कर सकते हैं इन संपीड़न स्तरों के। महत्वपूर्ण बात यह है कि कोई असम्पीडित अनुक्रमणिका या विभाजन नहीं हैं।
NULL
से बदल रहा है करने के लिएNOT NULL
अनुमति नहीं है ।- निम्न पूर्णांक प्रकार में परिवर्तन समर्थित हैं:
smallint
सेinteger
याbigint
।integer
करने के लिएbigint
।smallmoney
money
. के लिए (आंतरिक रूप से पूर्णांक प्रतिनिधित्व का उपयोग करता है)।
- निम्न स्ट्रिंग और बाइनरी प्रकार में परिवर्तन समर्थित हैं:
char(n)
करने के लिएchar(m)
याvarchar(m)
nchar(n)
सेnchar(m)
याnvarchar(m)
binary(n)
करने के लिएbinary(m)
याvarbinary(m)
- उपरोक्त सभी केवल
n < m
. के लिए औरm != max
- संयोजन परिवर्तन अनुमति नहीं हैं
ये परिवर्तन केवल मेटाडेटा हो सकते हैं क्योंकि अंतर्निहित बाइनरी डेटा लेआउट तब नहीं बदलता है जब कॉलम डिस्क्रिप्टर पंक्ति प्रारूप का उपयोग किया जाता है (इसलिए संपीड़न की आवश्यकता)। संपीड़न के बिना, पंक्ति संग्रह मूल FixedVar . का उपयोग करता है प्रतिनिधित्व, जो भौतिक लेआउट को फिर से लिखे बिना इन निश्चित-लंबाई वाले डेटा प्रकार परिवर्तनों को समायोजित नहीं कर सकता है।
आप देख सकते हैं कि tinyint
पूर्णांक प्रकार सूची से छोड़ा गया है। ऐसा इसलिए है क्योंकि यह अहस्ताक्षरित है, जबकि अन्य पूर्णांक प्रकार सभी हस्ताक्षरित हैं, इसलिए केवल मेटाडेटा परिवर्तन संभव नहीं है। उदाहरण के लिए, 255 का मान tinyint
. के लिए एक बाइट में फ़िट हो सकता है , लेकिन किसी भी हस्ताक्षरित प्रारूप में दो बाइट्स की आवश्यकता होती है। संपीड़ित होने पर हस्ताक्षरित प्रारूप -128 से +127 तक एक बाइट में हो सकते हैं।
पूर्णांक उदाहरण
इस सुधार का एक बहुत ही आसान अनुप्रयोग IDENTITY
. के साथ कॉलम के डेटा प्रकार को बदल रहा है संपत्ति।
मान लें कि हमारे पास पंक्ति संपीड़न का उपयोग करके निम्न ढेर तालिका है (पृष्ठ संपीड़न भी काम करेगा):
DROP TABLE IF EXISTS dbo.Test; GO CREATE TABLE dbo.Test ( id integer IDENTITY NOT NULL, some_value integer NOT NULL ) WITH (DATA_COMPRESSION = ROW);
आइए डेटा की 5 मिलियन पंक्तियाँ जोड़ें। यह स्पष्ट करने के लिए पर्याप्त होगा (प्रदर्शन के दृष्टिकोण से) कि कॉलम डेटा प्रकार बदलना केवल मेटाडेटा ऑपरेशन है या नहीं:
WITH Numbers AS ( SELECT n = ROW_NUMBER() OVER (ORDER BY @@SPID) FROM sys.all_columns AS AC1 CROSS JOIN sys.all_columns AS AC2 ORDER BY n OFFSET 0 ROWS FETCH FIRST 5 * 1000 * 1000 ROWS ONLY ) INSERT dbo.Test WITH (TABLOCKX) ( some_value ) SELECT N.n FROM Numbers AS N;
इसके बाद हम IDENTITY
का शोध करेंगे ऐसा प्रतीत करने के लिए कि हम लगभग उन मूल्यों से बाहर निकलने के बिंदु पर हैं जो एक integer
में फिट होंगे :
DBCC CHECKIDENT ( N'dbo.Test', RESEED, 2147483646 );
हम एक और पंक्ति सफलतापूर्वक जोड़ सकते हैं:
INSERT dbo.Test (some_value) VALUES (123456);
लेकिन एक और पंक्ति जोड़ने का प्रयास:
INSERT dbo.Test (some_value) VALUES (7890);
एक त्रुटि संदेश में परिणाम:
संदेश 8115, स्तर 16, राज्य 1, पंक्ति 1अंकगणित अतिप्रवाह त्रुटि पहचान को डेटा प्रकार int में परिवर्तित कर रही है।
हम कॉलम को bigint
. में बदलकर इसे ठीक कर सकते हैं :
ALTER TABLE dbo.Test ALTER COLUMN id bigint NOT NULL;
SQL सर्वर 2016 में सुधार के लिए धन्यवाद, यह आदेश केवल मेटाडेटा बदलता है , और तुरंत पूरा करता है। पिछला INSERT
कथन (जिसने अंकगणित अतिप्रवाह त्रुटि को फेंक दिया) अब सफलतापूर्वक पूरा हो गया है।
यह नई क्षमता IDENTITY
. के साथ कॉलम के प्रकार को बदलने से संबंधित सभी मुद्दों को हल नहीं करती है संपत्ति। हमें अभी भी कॉलम पर किसी भी इंडेक्स को छोड़ना और फिर से बनाना होगा, किसी भी संदर्भित विदेशी कुंजी को फिर से बनाना होगा, और इसी तरह। यह इस पोस्ट के दायरे से थोड़ा बाहर है (हालाँकि हारून बर्ट्रेंड ने इसके बारे में पहले भी लिखा है)। मेटाडेटा-ओनली ऑपरेशन के रूप में प्रकार को बदलने में सक्षम होने के कारण निश्चित रूप से चोट नहीं लगती है। सावधानीपूर्वक योजना के साथ, आवश्यक अन्य चरणों को यथासंभव कुशल बनाया जा सकता है, उदाहरण के लिए न्यूनतम लॉग या ONLINE
का उपयोग करना संचालन।
सिंटैक्स से सावधान रहें
सुनिश्चित करें कि हमेशा निर्दिष्ट करें NULL
या NOT NULL
ALTER COLUMN
. के साथ डेटा प्रकार बदलते समय . उदाहरण के लिए कहें कि हम some_value
. के डेटा प्रकार को भी बदलना चाहते हैं हमारे परीक्षण तालिका में कॉलम integer NOT NULL
. से करने के लिए bigint NOT NULL
।
जब हम कमांड लिखते हैं, तो हम NULL
. को छोड़ देते हैं या NOT NULL
क्वालीफायर:
ALTER TABLE dbo.Test ALTER COLUMN some_value bigint;
यह आदेश केवल मेटाडेटा परिवर्तन के रूप में सफलतापूर्वक पूरा होता है, लेकिन NOT NULL
. को भी हटाता है बाधा कॉलम अब bigint NULL
है , जो हमारा इरादा नहीं है। यह व्यवहार प्रलेखित है, लेकिन इसे अनदेखा करना आसान है।
हम निम्न के साथ अपनी गलती को ठीक करने का प्रयास कर सकते हैं:
ALTER TABLE dbo.Test ALTER COLUMN some_value bigint NOT NULL;
यह नहीं है एक मेटाडेटा-केवल परिवर्तन। हमें NULL
. से बदलने की अनुमति नहीं है करने के लिए NOT NULL
(यदि आपको शर्तों पर पुनश्चर्या की आवश्यकता है तो पिछली तालिका को देखें)। SQL सर्वर को यह सुनिश्चित करने के लिए सभी मौजूदा मानों की जांच करने की आवश्यकता होगी कि कोई नल मौजूद नहीं है। इसके बाद यह भौतिक रूप से हर पंक्ति को फिर से लिखेगा तालिका के। अपने आप में धीमी होने के साथ-साथ, ये कार्रवाइयाँ बड़ी मात्रा में लेन-देन लॉग उत्पन्न करती हैं, जिसका नॉक-ऑन प्रभाव हो सकता है।
एक साइड नोट के रूप में, IDENTITY
. वाले कॉलम के लिए भी यही गलती संभव नहीं है संपत्ति। अगर हम एक ALTER COLUMN
लिखते हैं NULL
के बिना स्टेटमेंट या NOT NULL
उस स्थिति में, इंजन मददगार रूप से मानता है कि हमारा मतलब NOT NULL
. है क्योंकि अशक्त स्तंभों पर पहचान संपत्ति की अनुमति नहीं है। इस व्यवहार पर भरोसा न करना अभी भी एक अच्छा विचार है।
हमेशा NULL
निर्दिष्ट करें या NOT NULL
ALTER COLUMN
. के साथ ।
संयोजन
डेटाबेस के लिए डिफ़ॉल्ट से मेल नहीं खाने वाले कोलेशन वाले स्ट्रिंग कॉलम को बदलते समय विशेष देखभाल की आवश्यकता होती है।
उदाहरण के लिए, मान लें कि हमारे पास केस के साथ एक टेबल है- और एक्सेंट-सेंसिटिव कॉलेशन (मान लें कि डेटाबेस डिफॉल्ट अलग है):
DROP TABLE IF EXISTS dbo.Test2; GO CREATE TABLE dbo.Test2 ( id integer IDENTITY NOT NULL, some_string char(8) COLLATE Latin1_General_100_CS_AS NOT NULL ) WITH (DATA_COMPRESSION = ROW);
डेटा की 50 लाख पंक्तियां जोड़ें:
WITH Numbers AS ( SELECT n = ROW_NUMBER() OVER (ORDER BY @@SPID) FROM sys.all_columns AS AC1 CROSS JOIN sys.all_columns AS AC2 ORDER BY n OFFSET 0 ROWS FETCH FIRST 5 * 1000 * 1000 ROWS ONLY ) INSERT dbo.Test2 WITH (TABLOCKX) ( some_string ) SELECT CONVERT(char(8), N.n) COLLATE Latin1_General_100_CS_AS FROM Numbers AS N;
निम्नलिखित कमांड का उपयोग करके स्ट्रिंग कॉलम की लंबाई को दोगुना करें:
ALTER TABLE dbo.Test2 ALTER COLUMN some_string char(16) NOT NULL;
हमें NOT NULL
निर्दिष्ट करना याद आया , लेकिन गैर-डिफ़ॉल्ट संयोजन के बारे में भूल गए। SQL सर्वर मानता है कि हम संयोजन को डेटाबेस डिफ़ॉल्ट में बदलना चाहते हैं (Latin1_General_CI_AS
मेरे परीक्षण डेटाबेस के लिए)। कोलेशन बदलना ऑपरेशन को केवल मेटाडेटा होने से रोकता है, और इसलिए ऑपरेशन कई मिनट तक चलता है, जिससे लॉग का ढेर बनता है।
पिछली स्क्रिप्ट का उपयोग करके तालिका और डेटा को फिर से बनाएं, फिर ALTER COLUMN
. आज़माएं फिर से कमांड करें, लेकिन मौजूदा गैर-डिफ़ॉल्ट संयोजन को कमांड के हिस्से के रूप में निर्दिष्ट करें:
ALTER TABLE dbo.Test2 ALTER COLUMN some_string char(16) COLLATE Latin1_General_100_CS_AS NOT NULL;
परिवर्तन अब केवल-मेटाडेटा कार्रवाई के रूप में तुरंत पूर्ण हो जाता है। जैसा कि NULL
. के साथ है और NOT NULL
वाक्य रचना, यह दुर्घटनाओं से बचने के लिए स्पष्ट होने का भुगतान करता है। यह सामान्य रूप से अच्छी सलाह है, न कि केवल ALTER COLUMN
. के लिए ।
संपीड़न
कृपया ध्यान रखें कि प्रत्येक सूचकांक के लिए संपीड़न को स्पष्ट रूप से निर्दिष्ट करने की आवश्यकता है, और आधार तालिका के लिए अलग से यदि यह एक ढेर है। यह एक और उदाहरण है जहां संक्षिप्त वाक्य रचना या शॉर्टकट का उपयोग करने से वांछित परिणाम को रोका जा सकता है।
उदाहरण के लिए, निम्न तालिका प्राथमिक कुंजी या इन-लाइन इंडेक्स परिभाषा के लिए स्पष्ट संपीड़न निर्दिष्ट नहीं करती है:
CREATE TABLE dbo.Test ( id integer IDENTITY NOT NULL PRIMARY KEY, some_value integer NOT NULL INDEX [IX dbo.Test some_value] ) WITH (DATA_COMPRESSION = PAGE);
PRIMARY KEY
एक नाम असाइन किया जाएगा, डिफ़ॉल्ट रूप से CLUSTERED
,और PAGE
be बनें दबा हुआ। इन-लाइन इंडेक्स NONCLUSTERED
होगा और बिल्कुल भी संकुचित नहीं। यह तालिका किसी भी नए अनुकूलन के लिए सक्षम नहीं होगी क्योंकि सभी अनुक्रमणिका और विभाजन संकुचित नहीं हैं।
एक बेहतर, और अधिक स्पष्ट तालिका परिभाषा होगी:
CREATE TABLE dbo.Test ( id integer IDENTITY NOT NULL CONSTRAINT [PK dbo.Test id] PRIMARY KEY CLUSTERED WITH (DATA_COMPRESSION = PAGE), some_value integer NOT NULL INDEX [IX dbo.Test some_value] NONCLUSTERED WITH (DATA_COMPRESSION = ROW) );
यह तालिका नए अनुकूलन के लिए योग्य होगी क्योंकि सभी अनुक्रमणिका और विभाजन संकुचित हैं। जैसा कि पहले उल्लेख किया गया है, संपीड़न प्रकारों को मिलाना ठीक है।
इसे लिखने के कई तरीके हैं CREATE TABLE
एक स्पष्ट तरीके से बयान, इसलिए व्यक्तिगत वरीयता का एक तत्व है। महत्वपूर्ण बिंदु यह है कि हमेशा स्पष्ट रहें आप क्या चाहते हैं के बारे में। यह अलग CREATE INDEX
. पर लागू होता है बयान भी।
विस्तारित इवेंट और ट्रेस फ़्लैग
विशेष रूप से केवल-नए मेटाडेटा के लिए एक विस्तारित ईवेंट है ALTER COLUMN
SQL सर्वर 2016 में समर्थित संचालन।
विस्तारित घटना compressed_alter_column_is_md_only
. है डीबग . में चैनल। इसके ईवेंट फ़ील्ड object_id
. हैं , column_id
, और is_md_only
(सच/झूठा)।
यह घटना केवल तभी इंगित करती है जब कोई कार्रवाई केवल SQL सर्वर 2016 की नई क्षमताओं के कारण मेटाडेटा है। स्तंभ परिवर्तन जो केवल 2016 से पहले मेटाडेटा थे, वे is_md_only = false
दिखाएंगे। अभी भी केवल मेटाडेटा होने के बावजूद।
ALTER COLUMN
. पर नज़र रखने के लिए उपयोगी अन्य विस्तारित ईवेंट संचालन में शामिल हैं metadata_ddl_alter_column
और alter_column_event
, दोनों विश्लेषणात्मक . में चैनल।
क्या आपको अक्षम करने की आवश्यकता है किसी भी कारण से नई SQL सर्वर 2016 क्षमताओं, अनिर्दिष्ट वैश्विक (या स्टार्ट-अप) ट्रेस ध्वज 3618 का उपयोग किया जा सकता है। सत्र स्तर पर उपयोग किए जाने पर यह ट्रेस ध्वज प्रभावी नहीं होता है। ALTER COLUMN
. के साथ क्वेरी-स्तरीय ट्रेस फ़्लैग निर्दिष्ट करने का कोई तरीका नहीं है आदेश।
अंतिम विचार
केवल-मेटाडेटा परिवर्तन के साथ कुछ निश्चित-लंबाई पूर्णांक डेटा प्रकारों को बदलने में सक्षम होना एक बहुत ही स्वागत योग्य उत्पाद सुधार है। यह आवश्यक है कि तालिका पहले से ही पूरी तरह से संकुचित हो, लेकिन वैसे भी यह एक सामान्य बात होती जा रही है। यह विशेष रूप से सच है क्योंकि SQL सर्वर 2016 सर्विस पैक 1 से शुरू होने वाले सभी संस्करणों में संपीड़न सक्षम किया गया था।
निश्चित-लंबाई वाले स्ट्रिंग प्रकार के कॉलम शायद बहुत कम आम हैं। इनमें से कुछ स्थान के उपयोग जैसे कुछ पुराने विचारों के कारण हो सकते हैं। संपीड़ित होने पर, निश्चित-लंबाई वाले स्ट्रिंग कॉलम अनुगामी रिक्त स्थान को संग्रहीत नहीं करते हैं, जिससे वे भंडारण बिंदु से चर-लंबाई वाले स्ट्रिंग कॉलम के समान ही कुशल हो जाते हैं। हेरफेर या प्रदर्शन के लिए रिक्त स्थान को ट्रिम करना कष्टप्रद हो सकता है, लेकिन यदि डेटा आमतौर पर अधिकतम लंबाई पर कब्जा कर लेता है, तो निश्चित-लंबाई वाले प्रकारों के महत्वपूर्ण लाभ हो सकते हैं, कम से कम सॉर्टिंग और हैशिंग जैसी चीजों के लिए मेमोरी अनुदान के संबंध में नहीं।
संपीड़न सक्षम होने के साथ यह सभी अच्छी खबर नहीं है। मैंने पहले उल्लेख किया था कि SQL सर्वर कभी-कभी मेटाडेटा-केवल परिवर्तन कर सकता है यह जाँचने के बाद कि सभी मौजूदा मान सफलतापूर्वक नए प्रकार में परिवर्तित हो जाएंगे। ALTER COLUMN
. का उपयोग करते समय यही स्थिति होती है integer
. से बदलने के लिए करने के लिए tinyint
उदाहरण के लिए। दुर्भाग्य से, ये ऑपरेशन वर्तमान में केवल संकुचित वस्तुओं के लिए मेटाडेटा नहीं हैं।
पावती
पैनागियोटिस एंटोनोपोलोस . के लिए विशेष धन्यवाद (प्रिंसिपल सॉफ्टवेयर इंजीनियर) और मिरेक स्ज़्टाजनो (सीनियर प्रोग्राम मैनेजर) SQL सर्वर उत्पाद टीम से इस लेख के शोध और लेखन के दौरान उनकी सहायता और मार्गदर्शन के लिए।
इस कार्य में दिए गए किसी भी विवरण को आधिकारिक Microsoft दस्तावेज़ या उत्पाद विवरण नहीं माना जाना चाहिए।