Czy jest jakiś sposób na zmianę typu danych kolumny jako operacji tylko na metadanych?
Nie sądzę, tak właśnie działa ten produkt. Istnieje kilka naprawdę dobrych obejść tego ograniczenia zaproponowanego w odpowiedzi Joe .
... powoduje, że SQL Server przepisuje całą tabelę (i używa 2x rozmiaru tabeli w obszarze dziennika)
Odpowiem na dwie części tego oświadczenia osobno.
Przepisywanie tabeli
Jak wspomniałem wcześniej, tak naprawdę nie da się tego uniknąć. Wydaje się, że taka jest sytuacja, nawet jeśli nie ma to pełnego sensu z naszej perspektywy jako klientów.
Spojrzenie na DBCC PAGE
przed i po zmianie kolumny z 4000 na 260 pokazuje, że wszystkie dane są powielone na stronie danych (moja tabela testowa miała 'A'
260 razy w rzędzie):
W tym momencie na stronie znajdują się dwie kopie dokładnie takich samych danych. „Stara” kolumna jest zasadniczo usuwana (identyfikator jest zmieniany z id = 2 na id = 67108865), a „nowa” wersja kolumny jest aktualizowana, aby wskazywała nowe przesunięcie danych na stronie:
Używanie 2x rozmiaru tabeli w obszarze dziennika
Dodanie WITH (ONLINE = ON)
na końcu ALTER
instrukcji zmniejsza aktywność rejestrowania o około połowę , więc jest to jedno ulepszenie, które można wprowadzić, aby zmniejszyć ilość potrzebnych zapisów na dysku / dysku.
Użyłem tej uprzęży testowej, aby ją wypróbować:
USE [master];
GO
DROP DATABASE IF EXISTS [248749];
GO
CREATE DATABASE [248749]
ON PRIMARY
(
NAME = N'248749',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\DATA\248749.mdf',
SIZE = 2048000KB,
FILEGROWTH = 65536KB
)
LOG ON
(
NAME = N'248749_log',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\DATA\248749_log.ldf',
SIZE = 2048000KB,
FILEGROWTH = 65536KB
);
GO
USE [248749];
GO
CREATE TABLE dbo.[table]
(
id int IDENTITY(1,1) NOT NULL,
[col] nvarchar (4000) NULL,
CONSTRAINT [PK_test] PRIMARY KEY CLUSTERED (id ASC)
);
INSERT INTO dbo.[table]
SELECT TOP (1000000)
REPLICATE(N'A', 260)
FROM master.dbo.spt_values v1
CROSS JOIN master.dbo.spt_values v2
CROSS JOIN master.dbo.spt_values v3;
GO
Sprawdziłem sys.dm_io_virtual_file_stats(DB_ID(N'248749'), DEFAULT)
przed i po uruchomieniu ALTER
instrukcji, a oto różnice:
Domyślnie (offline) ALTER
- Plik danych zapisuje / zapisuje bajty: 34 809/2 193,801,216
- Zapis pliku dziennika / zapisane bajty: 40 953/1 484 910 080
online ALTER
- Zapis / zapis danych w pliku danych: 36 874/1 693 745 152 (spadek o 22,8%)
- Zapis pliku dziennika / zapisane bajty: 24.680 / 866,166,272 (spadek o 41%)
Jak widać, nastąpił niewielki spadek zapisów pliku danych i znaczny spadek zapisów pliku dziennika.