इस महीने के टी-एसक्यूएल मंगलवार को माइक डोनेली (@SQLMD) द्वारा होस्ट किया जा रहा है, और वह इस विषय को इस प्रकार बताता है:
इस महीने का विषय सीधा है, लेकिन बहुत खुला है। आपको कुछ नया सीखना चाहिए और फिर उसे समझाते हुए एक ब्लॉग पोस्ट लिखना चाहिए।ठीक है, जिस क्षण से माइक ने विषय की घोषणा की, मैं वास्तव में कुछ भी नया सीखने के लिए तैयार नहीं था, और जैसे-जैसे सप्ताहांत निकट आया और मुझे पता था कि सोमवार जूरी ड्यूटी के साथ मुझ पर हमला करने वाला था, मुझे लगा कि मुझे यह बैठना होगा। महीना खत्म।
फिर, मार्टिन स्मिथ ने मुझे कुछ ऐसा सिखाया जिसे मैं या तो कभी नहीं जानता था, या बहुत पहले से जानता था लेकिन भूल गया हूं (कभी-कभी आप नहीं जानते कि आप क्या नहीं जानते हैं, और कभी-कभी आपको वह याद नहीं रहता जो आप कभी नहीं जानते थे और जो आप नहीं कर सकते थे याद रखना)। मुझे याद आया कि NOT NULL
. से एक कॉलम बदलना था करने के लिए NULL
चाहिए एक मेटाडेटा-ओनली ऑपरेशन हो, जिसमें किसी भी पेज को लिखने को तब तक के लिए टाल दिया जाता है जब तक कि उस पेज को अन्य कारणों से अपडेट नहीं किया जाता है, क्योंकि NULL
बिटमैप को वास्तव में तब तक मौजूद रहने की आवश्यकता नहीं होगी जब तक कि कम से कम एक पंक्ति NULL
न बन जाए ।
उसी पोस्ट पर, @ypercube ने मुझे बुक्स ऑनलाइन (टाइपो और सभी) के इस प्रासंगिक उद्धरण की भी याद दिलाई:
एक कॉलम को NOT NULL से NULL में बदलना एक ऑनलाइन ऑपरेशन के रूप में समर्थित नहीं है, जब परिवर्तित कॉलम नॉनक्लस्टर इंडेक्स द्वारा संदर्भ होता है।"ऑनलाइन ऑपरेशन नहीं" की व्याख्या "केवल मेटाडेटा-ऑपरेशन नहीं" के रूप में की जा सकती है - जिसका अर्थ है कि यह वास्तव में एक आकार का डेटा ऑपरेशन होगा (आपका इंडेक्स जितना बड़ा होगा, इसमें उतना ही अधिक समय लगेगा)।
मैंने इसे NOT NULL
से कनवर्ट करने के लिए एक विशिष्ट लक्ष्य कॉलम के विरुद्ध एक बहुत ही सरल (लेकिन लंबा) प्रयोग के साथ साबित करने के लिए निर्धारित किया है करने के लिए NULL
. मैं 3 टेबल बनाउंगा, सभी क्लस्टर प्राथमिक कुंजी के साथ, लेकिन प्रत्येक एक अलग गैर-संकुल सूचकांक के साथ। एक में लक्ष्य कॉलम कुंजी कॉलम के रूप में होगा, दूसरा INCLUDE
. के रूप में होगा कॉलम, और तीसरा लक्ष्य कॉलम का बिल्कुल भी संदर्भ नहीं देगा।
यहां मेरी टेबल हैं और मैंने उन्हें कैसे पॉप्युलेट किया:
CREATE TABLE dbo.test1 ( a INT NOT NULL, b INT NOT NULL, c BIGINT NOT NULL, CONSTRAINT pk_t1 PRIMARY KEY (a,b) ); GO CREATE NONCLUSTERED INDEX ix1 ON dbo.test1(b,c); GO CREATE TABLE dbo.test2 ( a INT NOT NULL, b INT NOT NULL, c BIGINT NOT NULL, CONSTRAINT pk_t2 PRIMARY KEY (a,b) ); GO CREATE NONCLUSTERED INDEX ix2 ON dbo.test2(b) INCLUDE(c); GO CREATE TABLE dbo.test3 ( a INT NOT NULL, b INT NOT NULL, c BIGINT NOT NULL, CONSTRAINT pk_t3 PRIMARY KEY (a,b) ); GO CREATE NONCLUSTERED INDEX ix3 ON dbo.test3(b); GO INSERT dbo.test1(a,b,c) -- repeat for test2 / test3 SELECT n1, n2, ABS(n2)-ABS(n1) FROM ( SELECT TOP (100000) s1.[object_id], s2.[object_id] FROM master.sys.all_objects AS s1 CROSS JOIN master.sys.all_objects AS s2 GROUP BY s1.[object_id], s2.[object_id] ) AS n(n1, n2);
प्रत्येक तालिका में 100,000 पंक्तियाँ थीं, संकुल अनुक्रमणिका में 310 पृष्ठ थे, और गैर-संकुल अनुक्रमणिका में 272 पृष्ठ थे (test1
और test2
) या 174 पृष्ठ (test3
) (ये मान sys.dm_db_index_physical_stats
से प्राप्त करना आसान है ।)
इसके बाद, मुझे पृष्ठ स्तर पर लॉग किए गए कार्यों को कैप्चर करने का एक आसान तरीका चाहिए - मैंने sys.fn_dblog()
चुना , हालांकि मैं और गहरा खोद सकता था और सीधे पृष्ठों को देख सकता था। मैंने फ़ंक्शन को पास करने के लिए एलएसएन मूल्यों के साथ खिलवाड़ करने की जहमत नहीं उठाई, क्योंकि मैं इसे उत्पादन में नहीं चला रहा था और प्रदर्शन के बारे में ज्यादा परवाह नहीं करता था, इसलिए परीक्षणों के बाद मैंने किसी भी डेटा को छोड़कर फ़ंक्शन के परिणामों को छोड़ दिया। ALTER TABLE
. से पहले लॉग किया गया था संचालन।
-- establish an exclusion set SELECT * INTO #x FROM sys.fn_dblog(NULL, NULL);
अब मैं अपने परीक्षण चला सकता था, जो सेटअप की तुलना में बहुत आसान थे।
ALTER TABLE dbo.test1 ALTER COLUMN c BIGINT NULL; ALTER TABLE dbo.test2 ALTER COLUMN c BIGINT NULL; ALTER TABLE dbo.test3 ALTER COLUMN c BIGINT NULL;
अब मैं प्रत्येक मामले में लॉग किए गए कार्यों की जांच कर सकता था:
SELECT AllocUnitName, [Operation], Context, c = COUNT(*) FROM ( SELECT * FROM sys.fn_dblog(NULL, NULL) WHERE [Operation] = N'LOP_FORMAT_PAGE' AND AllocUnitName LIKE N'dbo.test%' EXCEPT SELECT * FROM #x ) AS x GROUP BY AllocUnitName, [Operation], Context ORDER BY AllocUnitName, [Operation], Context;
परिणाम बताते हैं कि गैर-संकुल सूचकांक के प्रत्येक पृष्ठ पृष्ठ को उन मामलों के लिए स्पर्श किया जाता है जहां किसी भी तरह से सूचकांक में लक्ष्य स्तंभ का उल्लेख किया गया था, लेकिन उस मामले के लिए ऐसा कोई संचालन नहीं होता है जहां लक्ष्य स्तंभ का उल्लेख नहीं किया गया है। गैर-संकुल सूचकांक:
वास्तव में, पहले दो मामलों में, नए पृष्ठ आवंटित किए जाते हैं (आप इसकी पुष्टि DBCC IND
से कर सकते हैं) , जैसा कि स्पोरी ने अपने उत्तर में किया था), इसलिए ऑपरेशन ऑनलाइन हो सकता है, लेकिन इसका मतलब यह नहीं है कि यह तेज़ है (क्योंकि इसे अभी भी उस सभी डेटा की एक प्रति लिखनी है, और NULL
बनाना है। बिटमैप प्रत्येक नए पृष्ठ को लिखने के भाग के रूप में बदलता है, और उस सभी गतिविधि को लॉग करता है)।
मुझे लगता है कि ज्यादातर लोगों को संदेह होगा कि NOT NULL
. से एक कॉलम बदलना करने के लिए NULL
केवल सभी परिदृश्यों में मेटाडेटा होगा, लेकिन मैंने यहां दिखाया है कि यह सच नहीं है यदि कॉलम को गैर-संकुल सूचकांक द्वारा संदर्भित किया जाता है (और इसी तरह की चीजें होती हैं चाहे वह एक कुंजी हो या INCLUDE
कॉलम)। शायद इस ऑपरेशन को ONLINE
करने के लिए भी मजबूर किया जा सकता है Azure SQL डेटाबेस में आज, या यह अगले प्रमुख संस्करण में संभव होगा? यह जरूरी नहीं कि वास्तविक भौतिक संचालन किसी भी तेजी से हो, लेकिन यह परिणामस्वरूप अवरुद्ध होने से रोकेगा।
मैंने उस परिदृश्य का परीक्षण नहीं किया (और यह विश्लेषण कि क्या यह वास्तव में ऑनलाइन है, वैसे भी Azure में कठिन है), और न ही मैंने इसे ढेर पर परीक्षण किया। कुछ मैं भविष्य की पोस्ट में फिर से देख सकता हूँ। इस बीच, केवल-मेटाडेटा संचालन के बारे में आपके द्वारा किए जा सकने वाले किसी भी अनुमान के बारे में सावधान रहें।