¿Hay alguna forma de alterar el tipo de datos de la columna como una operación de solo metadatos?
No lo creo, así es como funciona el producto en este momento. Hay algunas soluciones realmente buenas para esta limitación propuesta en la respuesta de Joe .
... da como resultado que SQL Server reescriba toda la tabla (y use un tamaño de tabla 2x en el espacio de registro)
Voy a responder a las dos partes de esa declaración por separado.
Reescribiendo la tabla
Como mencioné antes, en realidad no hay forma de evitar esto. Esa parece ser la realidad de la situación, incluso si no tiene sentido desde nuestra perspectiva como clientes.
Mirar DBCC PAGE
antes y después de cambiar la columna de 4000 a 260 muestra que todos los datos están duplicados en la página de datos (mi tabla de prueba tenía 'A'
260 veces seguidas):
En este punto, hay dos copias de los mismos datos exactos en la página. La columna "antigua" se elimina esencialmente (la identificación cambia de id = 2 a id = 67108865), y la versión "nueva" de la columna se actualiza para señalar el nuevo desplazamiento de los datos en la página:
Uso de 2x tamaño de tabla en espacio de registro
Agregar WITH (ONLINE = ON)
al final de la ALTER
declaración reduce la actividad de registro a la mitad , por lo que esta es una mejora que podría hacer para reducir la cantidad de escrituras en el disco / espacio en disco necesario.
Usé este arnés de prueba para probarlo:
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
Verifiqué sys.dm_io_virtual_file_stats(DB_ID(N'248749'), DEFAULT)
antes y después de ejecutar la ALTER
declaración, y aquí están las diferencias:
Predeterminado (sin conexión) ALTER
- Escrituras de archivo de datos / bytes escritos: 34,809 / 2,193,801,216
- Escrituras de archivo de registro / bytes escritos: 40,953 / 1,484,910,080
En línea ALTER
- Escrituras de archivo de datos / bytes escritos: 36,874 / 1,693,745,152 (22.8% de caída)
- Escrituras de archivo de registro / bytes escritos: 24,680 / 866,166,272 (41% de caída)
Como puede ver, hubo una ligera caída en las escrituras del archivo de datos y una caída importante en las escrituras del archivo de registro.