Bir sütunu NOT NULL değerinden NULL olarak değiştirme - Başlığın altında neler oluyor?


25

İçinde 2.3B satır bulunan bir tablomuz var. Bir sütunu NOT NULL değerinden NULL olarak değiştirmek istiyoruz. Sütun bir dizinde bulunur (kümelenmiş veya PK dizini değil). Veri türü değişmiyor (bu bir INT). Sadece null kabiliyeti. İfade aşağıdaki gibidir:

Alter Table dbo.Workflow Alter Column LineId Int NULL

İşlem durdurulmadan önce 10'dan fazla sürüyor (henüz tamamlanmasına bile izin vermedik, çünkü bu bir engelleme işlemi ve çok uzun sürüyordu). Muhtemelen tabloyu gerçekten ne kadar sürdüğünü test eden bir dev sunucuya kopyalayacağız. Ancak, SQL NULL’dan NULL’a dönüştürme yaparken SQL Server’ın kaputun altında ne yaptığını bilen var mı merak ediyorum. Ayrıca, etkilenen endekslerin yeniden oluşturulması gerekecek mi? Oluşturulan sorgu planı ne olduğunu göstermez.

Söz konusu tablo kümelenmiştir (bir yığın değildir).


2
Tüm yaprak seviyesi veri sayfalarındaki boş bitmap'i güncellemesi gerekeceğini düşünüyorum. Ve 2.3B satırlarla, üzerinde çalışacak çok fazla sayfa olacağına bahse girerim. Yine de bu konuda emin değilim.
souplex

3
Dizine boş bir bitmap koymak da meşgul olabilir. Dizin tanımının tüm bölümleri NOT NULL olarak tanımlanmışsa, NULL bitmap, CLUSTERED INDEX'te bulunmaz.
souplex

Yanıtlar:


27

Yorumlarda @Souplex tarafından belirtildiği gibi, olası bir açıklama, bu sütunun NULLkatıldığı kümelenmemiş dizindeki ilk kullanılabilen sütun ise olabilir .

Aşağıdaki kurulum için

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 

sys.dm_db_index_physical_stats kümelenmemiş dizinin ix248 yaprak sayfasına ve tek bir kök sayfaya sahip olduğunu gösterir.

Dizin yaprağı sayfasındaki tipik bir satır

görüntü tanımını buraya girin

Ve kök sayfada

görüntü tanımını buraya girin

Sonra koşuyor ...

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

İade

+-----------------+--------------------+-------------+----------------+
|    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 |
+-----------------+--------------------+-------------+----------------+

Dizin yaprağını tekrar kontrol etmek için satırlar şimdi

görüntü tanımını buraya girin

ve üst seviye sayfalardaki satırlar aşağıdaki gibidir.

görüntü tanımını buraya girin

Her satır güncellendi ve şimdi NULL_BITMAP için başka bir bayt ile birlikte sütun sayımı için iki bayt içeriyor.

Ekstra satır genişliği nedeniyle kümelenmemiş indeks artık kök sayfala birlikte 285 yaprak sayfasına ve şimdi iki orta seviye sayfaya sahiptir.

İçin İcra Planı

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

aşağıdaki gibi görünüyor

görüntü tanımını buraya girin

Bu, mevcut olanı güncellemek ve sayfaları bölmek zorunda kalmak yerine, dizinin yepyeni bir kopyasını oluşturur.


9

Kümelenmemiş dizini kesinlikle yeniden oluşturur ve yalnızca meta verileri güncellemez. Bu, SQL 2014'te test edilmiştir ve bir üretim sisteminde gerçekten test edilmemelidir:

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);

Ve şimdi eğlence kısmı için:

DBCC IND (0, z, -1)

Bu bize tablonun ve kümelenmemiş dizinin depolandığı veritabanı sayfalarını verecektir.

PagePIDNerede IndexID2 ve PageType2 olduğunu bulun ve sonra aşağıdakileri yapın:

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

ve sonra:

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

Üstbilgide boş bir bitmap olduğuna dikkat edin:

Sayfa başlığı özü

Şimdi yapalım:

alter table z alter Column b int null;

Eğer gerçekten sabırsızsanız, dbcc pagekomutu tekrar çalıştırmayı deneyebilirsiniz, ancak başarısız olur, bu nedenle tahsisi tekrar kontrol edelim DBCC IND (0, z, -1). Sayfa sanki sihir gibi hareket etmiş olacak.

Bu nedenle, bir sütunun düzenlenebilirliğinin değiştirilmesi, meta verilerin güncellenmesi gerektiğinden ve daha sonra dizinleri yeniden yapılandırmanız gerekmediğinden, bu sütunu kapsayan kümelenmemiş dizinlerin depolanmasını etkileyecektir.


SQL Server 2016'dan başlayarak birçok ALTER TABLE ... ALTER COLUMN ...işlem gerçekleştirilebilir ONLINE, ancak:

ALTER TABLE (Transact-SQL)

  • Bir sütun değiştirme NOT NULLTo NULLdeğişmiş kolon kümelenmemiş dizin tarafından başvuruda edildiğinde bir online işlem olarak desteklenmez.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.