NULL से NULL तक एक कॉलम बदलना - हुड के नीचे क्या हो रहा है?


25

हमारे पास एक तालिका है जिसमें 2.3B पंक्तियाँ हैं। हम एक कॉलम को NULL से NULL तक बदलना चाहेंगे। स्तंभ एक अनुक्रमणिका में निहित है (क्लस्टर या PK अनुक्रमणिका नहीं)। डेटा प्रकार बदल नहीं रहा है (यह एक INT है)। बस अशक्तता है। कथन इस प्रकार है:

Alter Table dbo.Workflow Alter Column LineId Int NULL

ऑपरेशन बंद होने से पहले 10 से अधिक लगते हैं (हमने इसे अभी तक पूरा नहीं होने दिया है क्योंकि यह एक अवरुद्ध ऑपरेशन है और बहुत लंबा समय लग रहा है)। हम शायद एक देव सर्वर के लिए तालिका की नकल करेंगे कि यह वास्तव में कितना समय लेता है। लेकिन, अगर किसी को पता नहीं है कि एसक्यूएल सर्वर हुड के नीचे क्या कर रहा है, तो क्या मुझे पता है कि जब NULL NULL से NULL में परिवर्तित नहीं होता है, तो मैं उत्सुक हूं? इसके अलावा, प्रभावित अनुक्रमितों को फिर से बनाने की आवश्यकता होगी? उत्पन्न क्वेरी प्लान इंगित नहीं करता है कि क्या हो रहा है।

विचाराधीन तालिका को क्लस्टर किया गया है (ढेर नहीं)।


2
मुझे लगता है कि यह सभी पत्ती स्तर के डाटापेज पर नल बिटमैप को अद्यतन करना होगा। और 2.3B पंक्तियों के साथ, मुझे यकीन है कि इसके माध्यम से काम करने के लिए बहुत सारे पृष्ठ होंगे। मैं हालांकि इस बारे में निश्चित नहीं हूं।
सूपरलेक्स

3
सूचकांक पर एक अशक्त बिटमैप रखने में व्यस्त हो सकता है। NULL-CLUSTERED INDEX में NULL बिटमैप मौजूद नहीं होगा यदि इंडेक्स परिभाषा के सभी कॉलम भाग को NULL के रूप में परिभाषित नहीं किया गया है।
सुप्लेक्स

जवाबों:


27

जैसा कि टिप्पणियों में @Souplex द्वारा किया गया था, एक संभावित स्पष्टीकरण यह हो सकता है कि यह कॉलम NULLगैर-संकुलित सूचकांक में पहला- सक्षम स्तंभ है, जिसमें यह भाग लेता है।

निम्नलिखित सेटअप के लिए

CREATE TABLE Foo
  (
     A UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
     B CHAR(1) NOT NULL DEFAULT 'B'
  )

CREATE NONCLUSTERED INDEX ix
  ON Foo(B);

INSERT INTO Foo
            (B)
SELECT TOP 100000 'B'
FROM   master..spt_values v1,
       master..spt_values v2 

sysinos_db_index_physical_stats दर्शाता है कि गैर-संकुल सूचकांक ixमें 248 पत्ती पृष्ठ और एक एकल रूट पृष्ठ है।

एक इंडेक्स लीफ पेज में एक विशिष्ट पंक्ति दिखती है

यहाँ छवि विवरण दर्ज करें

और रूट पेज में

यहाँ छवि विवरण दर्ज करें

फिर चल रहा है ...

CHECKPOINT;

GO

ALTER TABLE Foo ALTER COLUMN B  CHAR(1) NULL;


SELECT Operation, 
       Context,
       ROUND(SUM([Log Record Length]) / 1024.0,1) AS [Log KB],
       COUNT(*) as [OperationCount]
FROM sys.fn_dblog(NULL,NULL)
WHERE AllocUnitName = 'dbo.Foo.ix'
GROUP BY Operation, Context

लौटा हुआ

+-----------------+--------------------+-------------+----------------+
|    Operation    |      Context       |   Log KB    | OperationCount |
+-----------------+--------------------+-------------+----------------+
| LOP_SET_BITS    | LCX_GAM            | 4.200000    |             69 |
| LOP_FORMAT_PAGE | LCX_IAM            | 0.100000    |              1 |
| LOP_SET_BITS    | LCX_IAM            | 4.200000    |             69 |
| LOP_FORMAT_PAGE | LCX_INDEX_INTERIOR | 8.700000    |              3 |
| LOP_FORMAT_PAGE | LCX_INDEX_LEAF     | 2296.200000 |            285 |
| LOP_MODIFY_ROW  | LCX_PFS            | 16.300000   |            189 |
+-----------------+--------------------+-------------+----------------+

तर्जनी की जाँच फिर से पंक्तियों की तरह लग रही है

यहाँ छवि विवरण दर्ज करें

और नीचे के रूप में ऊपरी स्तर के पन्नों में पंक्तियाँ।

यहाँ छवि विवरण दर्ज करें

प्रत्येक पंक्ति को अपडेट कर दिया गया है और अब NULL_BITMAP के लिए एक अन्य बाइट के साथ कॉलम गणना के लिए दो बाइट्स हैं।

अतिरिक्त पंक्ति चौड़ाई के कारण नॉन क्लस्टर्ड इंडेक्स में अब 285 लीफ पेज और अब रूट पेज के साथ दो मध्यवर्ती स्तर के पेज हैं।

के लिए निष्पादन योजना

 ALTER TABLE Foo ALTER COLUMN B  CHAR(1) NULL;

इस प्रकार दिखता है

यहाँ छवि विवरण दर्ज करें

यह मौजूदा एक को अपडेट करने और पृष्ठों को विभाजित करने की आवश्यकता के बजाय सूचकांक की एक नई प्रतिलिपि बनाता है।


9

यह निश्चित रूप से नॉन क्लस्टर्ड इंडेक्स बनाएगा और सिर्फ मेटाडेटा अपडेट नहीं करेगा। यह SQL 2014 पर परीक्षण किया गया है और वास्तव में एक उत्पादन प्रणाली पर परीक्षण नहीं किया जाना चाहिए:

CREATE TABLE [z](
    [a] [int] IDENTITY(1,1) NOT NULL,
    [b] [int] NOT NULL,
 CONSTRAINT [c_a] PRIMARY KEY CLUSTERED  ([a] ASC))
go
CREATE NONCLUSTERED INDEX [nc_b] on z (b asc)
GO
insert into z (b)
values (1);

और अब मज़ेदार हिस्से के लिए:

DBCC IND (0, z, -1)

यह हमें डेटाबेस पेज देगा जहां टेबल और नॉन क्लस्टर्ड इंडेक्स को स्टोर किया जाता है।

पता लगाएं कि PagePIDकहां IndexID2 है और PageType2 है, और फिर निम्नलिखित करें:

DBCC TRACEON(3604) --are you sure that you are allowed to do this?

और फिर:

dbcc page (0, 1, PagePID, 3) with tableresults

ध्यान दें कि शीर्ष लेख में एक अशक्त बिटमैप है:

पेज हैडर एक्सट्रैक्ट

अब करते हैं:

alter table z alter Column b int null;

यदि आप वास्तव में अधीर हैं तो आप dbcc pageकमांड को फिर से चलाने का प्रयास कर सकते हैं, लेकिन यह विफल हो जाएगा, तो आइए आवंटन को फिर से जांचें DBCC IND (0, z, -1)। पेज जादू की तरह आगे बढ़ गया होगा।

तो एक कॉलम की बदलती अशक्तता उस कॉलम को कवर करने वाले गैर-क्लस्टर इंडेक्स के भंडारण को प्रभावित करेगी, क्योंकि मेटाडेटा को अपडेट करने की आवश्यकता है और आपको बाद में इंडेक्स को फिर से बनाने की आवश्यकता नहीं होनी चाहिए।


कई ALTER TABLE ... ALTER COLUMN ...ऑपरेशन ONLINESQL Server 2016 के साथ शुरू किए जा सकते हैं , लेकिन:

ALTER TABLE (Transact-SQL)

  • से एक कॉलम में फेरबदल NOT NULLकरने के लिए NULLजब बदल स्तंभ nonclustered अनुक्रमणिका द्वारा संदर्भित है एक ऑनलाइन आपरेशन के रूप में समर्थित नहीं है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.