Existe-t-il un moyen de modifier le type de données de colonne en tant qu'opération de métadonnées uniquement?
Je ne pense pas, c'est ainsi que fonctionne le produit en ce moment. Il existe de très bonnes solutions de contournement à cette limitation proposée dans la réponse de Joe .
... entraîne la réécriture de SQL Server de la table entière (et l'utilisation d'une taille de table 2x dans l'espace de journal)
Je vais répondre séparément aux deux parties de cette déclaration.
Réécrire la table
Comme je l'ai mentionné précédemment, il n'y a vraiment aucun moyen d'éviter cela. Cela semble être la réalité de la situation, même si cela n'a pas de sens de notre point de vue en tant que clients.
Regarder DBCC PAGE
avant et après avoir changé la colonne de 4000 en 260 montre que toutes les données sont dupliquées sur la page de données (ma table de test avait 'A'
260 fois de suite):
À ce stade, il existe deux copies des mêmes données exactes sur la page. La "vieille" colonne est essentiellement supprimée (l'ID est changé de id = 2 à id = 67108865), et la "nouvelle" version de la colonne est mise à jour pour pointer vers le nouveau décalage des données sur la page:
Utilisation de la taille de table 2x dans l'espace de journal
L'ajout WITH (ONLINE = ON)
à la fin de l' ALTER
instruction réduit l'activité de journalisation d'environ la moitié , c'est donc une amélioration que vous pourriez apporter pour réduire la quantité d'écritures sur le disque / l'espace disque nécessaire.
J'ai utilisé ce harnais de test pour l'essayer:
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
J'ai vérifié sys.dm_io_virtual_file_stats(DB_ID(N'248749'), DEFAULT)
avant et après l'exécution de l' ALTER
instruction, et voici les différences:
Par défaut (hors ligne) ALTER
- Écriture du fichier de données / octets écrits: 34,809 / 2,193,801,216
- Écriture du fichier journal / octets écrits: 40,953 / 1,484,910,080
En ligne ALTER
- Écriture du fichier de données / octets écrits: 36 874/1 693 745 152 (baisse de 22,8%)
- Écrits du fichier journal / octets écrits: 24,680 / 866,166,272 (baisse de 41%)
Comme vous pouvez le voir, il y a eu une légère baisse des écritures du fichier de données et une baisse importante des écritures du fichier journal.
update table set new_col = old_col where new_col <> old_col;
avant d'abandonnerold_col
.where new_col <> old_col
sans aucune autre clause de filtrage n'entraînera, vous pouvez ajouter un déclencheur pour reporter ces modifications au fur et à mesure et les supprimer à la fin du processus. Toujours un impact potentiel sur les performances, mais de nombreuses petites quantités sur la durée du processus au lieu d'un énorme hit à la fin, probablement (en fonction du modèle de mise à jour de votre application pour le tableau) totalisant beaucoup moins que cet énorme hit .Eh bien, il existe une alternative en fonction de l'espace disponible dans votre base de données.
Créez une copie exacte de votre tableau (par exemple
new_table
), à l'exception de la colonne où vous raccourcirez deNVARCHAR(4000)
àNVARCHAR(260)
:Dans une fenêtre de maintenance copiez les données de la table "cassée" (
table
) vers la table "fixe" (new_table
) avec un simpleINSERT ... INTO ... SELECT ....
:Renommez la table "cassée"
table
en quelque chose d'autre:Renommez la table "fixe"
new_table
entable
:Si tout va bien, supprimez le tableau renommé "cassé":
Voilà.
Répondre à vos questions
Non actuellement impossible
Non.
( Voir ma solution et d'autres. )
la source