[ भाग 1 | भाग 2 | भाग 3 | भाग 4 ]
एक समस्या जो मैंने हाल ही में कई बार देखी है, वह वह परिदृश्य है जहाँ आपने एक INT के रूप में एक पहचान कॉलम बनाया है, और अब ऊपरी सीमा के करीब है और इसे बड़ा (BIGINT) बनाने की आवश्यकता है। यदि आपकी तालिका इतनी बड़ी है कि आप एक पूर्णांक (2 बिलियन से अधिक) की ऊपरी सीमा तक पहुंच रहे हैं, तो यह एक ऐसा ऑपरेशन नहीं है जिसे आप मंगलवार को दोपहर के भोजन और अपने कॉफी ब्रेक के बीच कर सकते हैं। यह श्रृंखला इस तरह के बदलाव के पीछे यांत्रिकी का पता लगाएगी, और अपटाइम पर अलग-अलग प्रभावों के साथ इसे करने के विभिन्न तरीकों का पता लगाएगी। पहले भाग में, मैं किसी अन्य चर के बिना INT को BIGINT में बदलने के भौतिक प्रभाव पर करीब से नज़र डालना चाहता था।
जब आप INT का विस्तार करते हैं तो वास्तव में क्या होता है?
INT और BIGINT निश्चित आकार के डेटा प्रकार हैं, इसलिए एक से दूसरे में रूपांतरण को पृष्ठ को छूना पड़ता है, जिससे यह एक आकार का डेटा ऑपरेशन बन जाता है। यह प्रति-सहज है, क्योंकि ऐसा लगता है कि INT से BIGINT में डेटा प्रकार परिवर्तन के लिए तुरंत पृष्ठ पर अतिरिक्त स्थान की आवश्यकता के लिए संभव नहीं होगा (और एक पहचान कॉलम के लिए, हमेशा)। तार्किक रूप से सोचते हुए, यह वह स्थान है जिसकी संभवतः बाद में आवश्यकता नहीं हो सकती थी, जब एक मौजूदा INT मान को एक मान> 4 बाइट्स में बदल दिया गया था। लेकिन ऐसा नहीं है कि यह आज कैसे काम करता है। आइए एक साधारण तालिका बनाएं और देखें:
CREATE TABLE dbo.FirstTest ( RowID int IDENTITY(1,1), Filler char(2500) NOT NULL DEFAULT 'x' ); GO INSERT dbo.FirstTest WITH (TABLOCKX) (Filler) SELECT TOP (20) 'x' FROM sys.all_columns AS c; GO. से
एक साधारण क्वेरी मुझे इस ऑब्जेक्ट को आवंटित निम्न और उच्च पृष्ठ, साथ ही कुल पृष्ठ संख्या बता सकती है:
SELECT lo_page = MIN(allocated_page_page_id), hi_page = MAX(allocated_page_page_id), page_count = COUNT(*) FROM sys.dm_db_database_page_allocations ( DB_ID(), OBJECT_ID(N'dbo.FirstTest'), NULL, NULL, NULL );
अब अगर मैं डेटा प्रकार को INT से BIGINT में बदलने से पहले और बाद में उस क्वेरी को चलाता हूं:
ALTER TABLE dbo.FirstTest ALTER COLUMN RowID bigint;
मुझे ये परिणाम दिखाई दे रहे हैं:
-- before: lo_page hi_page page_count ------- ------- ---------- 243 303 17 -- after: lo_page hi_page page_count ------- ------- ---------- 243 319 33
यह स्पष्ट है कि आवश्यक अतिरिक्त स्थान के लिए जगह बनाने के लिए 16 नए पृष्ठ जोड़े गए थे (भले ही हम जानते हैं कि तालिका में किसी भी मान को वास्तव में 8 बाइट्स की आवश्यकता नहीं है)। लेकिन यह वास्तव में उस तरह से पूरा नहीं हुआ जैसा आप सोच सकते हैं - मौजूदा पृष्ठों पर कॉलम को चौड़ा करने के बजाय, पंक्तियों को नए पृष्ठों पर ले जाया गया, उनके स्थान पर पॉइंटर्स पीछे रह गए। पृष्ठ 243 को पहले और बाद में देख रहे हैं (बिना दस्तावेज़ के DBCC PAGE
):
-- ******** Page 243, before: ******** Slot 0 Offset 0x60 Length 12 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP Record Size = 12 Memory Dump @0x000000E34B9FA060 0000000000000000: 10000900 01000000 78020000 .. .....x... Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4 RowID = 1 Slot 0 Column 2 Offset 0x8 Length 1 Length (physical) 1 filler = x -- ******** Page 243, after: ******** Slot 0 Offset 0x60 Length 9 Record Type = FORWARDING_STUB Record Attributes = Record Size = 9 Memory Dump @0x000000E34B9FA060 0000000000000000: 04280100 00010078 01 .(.....x. Forwarding to = file 1 page 296 slot 376
फिर यदि हम पॉइंटर के लक्ष्य को देखें, पृष्ठ 296, स्लॉट 376, हम देखते हैं:
Slot 376 Offset 0x8ca Length 34 Record Type = FORWARDED_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS Record Size = 34 Memory Dump @0x000000E33BBFA8CA 0000000000000000: 32001100 01000000 78010000 00000000 00030000 2.......x........... 0000000000000014: 01002280 0004f300 00000100 0000 .."...ó....... Forwarded from = file 1 page 243 slot 0 Slot 376 Column 67108865 Offset 0x4 Length 0 Length (physical) 4 DROPPED = NULL Slot 376 Column 2 Offset 0x8 Length 1 Length (physical) 1 filler = x Slot 376 Column 1 Offset 0x9 Length 8 Length (physical) 8 RowID = 1
यह स्पष्ट रूप से तालिका की संरचना में एक बहुत ही विघटनकारी परिवर्तन है। (और एक दिलचस्प पक्ष अवलोकन:कॉलम, RowID और फिलर का भौतिक क्रम, पृष्ठ पर फ़्लिप किया गया है।) आरक्षित स्थान 136 केबी से 264 केबी तक कूदता है, और औसत विखंडन 33.3% से 40% तक मामूली रूप से बढ़ता है। यह स्थान एक पुनर्निर्माण, ऑनलाइन या नहीं, या एक रीऑर्ग द्वारा पुनर्प्राप्त नहीं किया जाता है, और - जैसा कि हम जल्द ही देखेंगे - ऐसा इसलिए नहीं है क्योंकि तालिका लाभ के लिए बहुत छोटी है।
नोट:यह SQL सर्वर 2016 के सबसे हाल के बिल्ड में भी सच है - जबकि इस तरह के अधिक से अधिक संचालन को आधुनिक संस्करणों में मेटाडेटा-केवल संचालन बनने के लिए सुधार किया गया है, यह अभी तक तय नहीं किया गया है, हालांकि स्पष्ट रूप से यह हो सकता है - फिर से, विशेष रूप से उस स्थिति में जहां कॉलम एक पहचान कॉलम है, जिसे परिभाषा के अनुसार अपडेट नहीं किया जा सकता है।
नए ALTER COLUMN / ONLINE सिंटैक्स के साथ ऑपरेशन करना, जिसके बारे में मैंने पिछले साल बात की थी, कुछ अंतर पैदा करता है:
-- drop / re-create here ALTER TABLE dbo.FirstTest ALTER COLUMN RowID bigint WITH (ONLINE = ON);
अब पहले और बाद में बन जाता है:
-- before: lo_page hi_page page_count ------- ------- ---------- 243 303 17 -- after: lo_page hi_page page_count ------- ------- ---------- 307 351 17
इस मामले में, यह अभी भी एक आकार का डेटा ऑपरेशन था, लेकिन ऑनलाइन विकल्प के कारण मौजूदा पृष्ठों की प्रतिलिपि बनाई गई और उन्हें फिर से बनाया गया। आपको आश्चर्य हो सकता है कि, जब हमने एक ऑनलाइन ऑपरेशन के रूप में कॉलम का आकार बदल दिया, तो तालिका अधिक डेटा को समान पृष्ठों में समेटने में सक्षम है? प्रत्येक पृष्ठ अब सघन है (कम पंक्तियाँ लेकिन प्रति पृष्ठ अधिक डेटा), बिखराव की कीमत पर - विखंडन 33.3% से 66.7% तक दोगुना हो जाता है। उपयोग किया गया स्थान उसी आरक्षित स्थान में अधिक डेटा दिखाता है (72 KB / 136 KB से 96 KB / 136 KB तक)।
और बड़े पैमाने पर?
आइए तालिका को छोड़ दें, इसे फिर से बनाएं, और इसे बहुत अधिक डेटा के साथ पॉप्युलेट करें:
CREATE TABLE dbo.FirstTest ( RowID INT IDENTITY(1,1), filler CHAR(1) NOT NULL DEFAULT 'x' ); GO INSERT dbo.FirstTest WITH (TABLOCKX) (filler) SELECT TOP (5000000) 'x' FROM sys.all_columns AS c1 CROSS JOIN sys.all_columns AS c2;
प्रारंभ से, अब हमारे पास 8,657 पृष्ठ हैं, 0.09% का विखंडन स्तर, और उपयोग की गई जगह 69,208 KB / 69,256 KB है।
यदि हम डेटा प्रकार को बिगिंट में बदलते हैं, तो हम 25,630 पृष्ठों पर कूद जाते हैं, विखंडन 0.06% तक कम हो जाता है, और उपयोग की जाने वाली जगह 205,032 केबी / 205,064 केबी है। एक ऑनलाइन पुनर्निर्माण कुछ भी नहीं बदलता है, न ही एक पुनर्गठन करता है। पुनर्निर्माण सहित पूरी प्रक्रिया में मेरी मशीन पर लगभग 97 सेकंड लगते हैं (डेटा जनसंख्या में सभी 2 सेकंड लगते हैं)।
यदि हम ऑनलाइन का उपयोग करके डेटा प्रकार को बिगिन्ट में बदलते हैं, तो बम्प केवल 11,140 पृष्ठों तक है, विखंडन 85.5% हो जाता है, और उपयोग की जाने वाली जगह 89,088 KB / 89160 KB है। ऑनलाइन पुनर्निर्माण और पुनर्गठन अभी भी कुछ भी नहीं बदलते हैं। इस बार, पूरी प्रक्रिया में केवल एक मिनट का समय लगता है। तो नया सिंटैक्स निश्चित रूप से तेज संचालन और कम अतिरिक्त डिस्क स्थान की ओर जाता है, लेकिन उच्च विखंडन। मैं ले लूँगा।
अगला
मुझे यकीन है कि आप ऊपर मेरे परीक्षण देख रहे हैं, और कुछ चीजों के बारे में सोच रहे हैं। सबसे महत्वपूर्ण बात यह है कि टेबल ढेर क्यों है? मैं यह जांचना चाहता था कि पृष्ठ संरचना और पृष्ठ गणना के साथ वास्तव में क्या होता है, जिसमें कोई अनुक्रमणिका, कुंजी, या विवरण को अस्पष्ट करने वाली बाधाएं नहीं होती हैं। आपको यह भी आश्चर्य हो सकता है कि यह परिवर्तन इतना आसान क्यों था - ऐसे परिदृश्य में जहां आपको एक वास्तविक पहचान कॉलम बदलना पड़ता है, यह शायद संकुल प्राथमिक कुंजी भी है, और अन्य तालिकाओं में विदेशी कुंजी निर्भरताएं हैं। यह निश्चित रूप से प्रक्रिया में कुछ हिचकी का परिचय देता है। हम श्रृंखला की अगली पोस्ट में इन बातों पर करीब से नज़र डालेंगे।
—
[ भाग 1 | भाग 2 | भाग 3 | भाग 4 ]