web-dev-qa-db-fra.com

Quel effet la réduction de la taille d'une colonne varchar aura-t-elle sur le fichier de base de données?

Nous avons un certain nombre de tables dans notre base de données qui ont des colonnes VARCHAR(MAX) où une VARCHAR(500) (ou quelque chose de beaucoup plus petit que max) suffira. Naturellement, je veux les nettoyer et ramener les tailles à des niveaux plus raisonnables. Le `` comment '' faire, je comprends: ma question est qu'est-ce que la modification de ces colonnes fera sur les pages et les extensions sur le disque? (Il y a beaucoup d'informations sur ce qui se passe lorsque vous développez une colonne, mais avoir du mal à trouver des informations sur ce qui se passe lorsque vous en réduisez une.)

Certaines tables ont un très petit nombre de lignes, donc je ne m'inquiète pas du coût du changement, mais certaines sont assez grandes, et je crains qu'elles soient potentiellement réorganisées et provoquent de nombreux blocages/temps d'arrêt. Concrètement, je veux juste un moyen d'estimer une fenêtre de maintenance. En général, j'aimerais mieux comprendre comment le moteur de base de données se comporte dans ce cas.

Merci d'avance!

MODIFIER:

J'ai 20 tables que je regarde, bien que seulement la moitié d'entre elles aient un nombre de lignes supérieur à 1 000. Le plus grand compte près d'un million de lignes. Le pire délinquant est une table avec 350 000 lignes et quatre colonnes VARCHAR(MAX) qui peuvent être réduites au niveau VARCHAR(500).

15
nateirvin

Tout d'abord: combien de données y a-t-il dans le tableau? Nombre de lignes et taille du tableau?

Deuxièmement: pouvez-vous sauvegarder et restaurer cette table sur un serveur de test et exécuter l'instruction alter pour voir l'impact (en supposant qu'elle n'est pas irréalisable car la table est trop grande pour tenir sur un système non-Production)? Je trouve toujours que les tests dans mon environnement sont plus précis que les conseils des interwebs car il y a plusieurs facteurs qui peuvent influencer le résultat qui pourraient ne pas être fournis dans la question simplement parce que je ne sais pas que ces facteurs pourraient affecter le résultat.

Troisièmement: augmente la taille d'un champ de longueur variable est (en supposant que vous ne dépassez pas la limite de 8060 octets) une simple opération de métadonnées depuis aucune donnée réelle ne changerait pour une telle opération. MAIS, d'autre part, réduire la taille d'un champ de longueur variable, même pour quelque chose qui fonctionnera plus qu'évidemment, est pas une simple méta -les données changent car SQL Server ne sait pas, avant d'analyser toutes les lignes, que la nouvelle taille demandée est valide.

Par conséquent: Oui, cela verrouillera la table pendant un certain temps . Combien de temps? Eh bien, voici le test que je viens de faire:

J'avais, à partir d'autres tests, une table avec un seul INT NOT NULL champ et 1 million de lignes. Je l'ai copié dans une nouvelle table dans le but de faire ce test via:

SELECT *, CONVERT(NVARCHAR(MAX), NEWID()) AS [StringField]
INTO dbo.ResizeTest
FROM dbo.ClusteredUnique;

De cette façon, je commençais avec un scénario similaire d'avoir un champ MAX (je viens de réaliser que vous avez VARCHAR et j'utilise NVARCHAR, mais cela ne devrait pas modifier la comportement que je vois) que je pourrais ensuite changer en 500. Et il contient des données qui peuvent facilement contenir jusqu'à 500 caractères. Cela a pris quelques minutes.

J'ai ensuite couru:

ALTER TABLE dbo.ResizeTest ALTER COLUMN [StringField] NVARCHAR(500) NULL;

Et cela a pris un peu plus de 11 minutes.

Je viens de relancer le test, cette fois en supprimant le [ResizeTest] table et en changeant les deux NVARCHARs pour être juste VARCHAR, juste pour être sûr que je compare les pommes à quelque chose qui ressemble au moins à un Apple = ;-).

La création initiale de la table a pris 20 secondes tandis que le ALTER TABLE a pris 2 minutes.

Donc, en termes d'estimation des temps d'arrêt, cela est vraiment difficile à faire car il est basé sur les vitesses d'E/S du disque, que des opérations de croissance automatique doivent ou non se produire sur le fichier de données et/ou le journal des transactions, etc. est probablement une grande partie de la raison pour laquelle mon premier test a pris 11 minutes à modifier et le second, même avec VARCHAR étant la moitié de la taille des données NVARCHAR, n'a pris que 2 minutes (c'est-à-dire que les fichiers étaient pré-cultivé à ce point). Mais encore, vous devez garder à l'esprit que mon test s'exécute sur mon ordinateur portable qui n'est pas le disque le plus rapide, mais ce n'était que 1 million de lignes de 2 petites colonnes (environ 22 octets par ligne).

Et puisque vous avez demandé ce que cela ferait aux pages de données, voici votre réponse. J'ai fait un sp_spaceused après avoir créé la table, après avoir fait le ALTER COLUMN, et après avoir fait ALTER TABLE dbo.ResizeTest REBUILD;. Les résultats (les nombres suivants sont basés sur le deuxième test utilisant VARCHAR, pas sur le premier test utilisant NVARCHAR):

After initial table creation:        526,344 KB
After ALTER COLUMN VARCHAR(500):   1,031,688 KB  <--- !! Yikes!!
After ALTER REBUILD:                 526,472 KB

Si vous êtes préoccupé par la nécessité de maintenir l'opération dans les plus brefs délais, consultez un article que j'ai écrit à ce sujet: Restructurer 100 millions de lignes (ou plus) de tables en secondes. SRSLY! ( inscription gratuite requise).

12
Solomon Rutzky

D'après ce que j'ai rassemblé, l'exécution de l'instruction alter ne devrait pas prendre très longtemps, car la table n'est pas verrouillée par un autre processus. Selon gbn, ce n'est qu'un changement de métadonnées: https://stackoverflow.com/questions/7261909/is-it-bad-to-use-alter-table-to-resize-a-varchar-column-to -une taille plus grande

En outre, quant à la façon dont ils sont stockés, il semble que SQL Server ait stocké les données varchar dans une page de 8 Ko jusqu'à ce qu'il remplisse une page entière, qui à ce stade, il la remplace par un pointeur et la stocke en tant que BLOB.

Je suppose que lorsque vous modifiez la longueur, vous ne tronquerez aucun enregistrement. Si c'est le cas, alors au maximum, les données que vous convertissez en varchar (500) doivent être, au maximum, de 502 octets et ne doivent pas avoir de pointeur.

Donc, pour faire court, peu de choses devraient changer tant que vous ne tronquez aucune donnée.

1
DForck42