Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Limitation des types de données sur une très grande table

Tout d'abord, merci d'avoir fait cela. C'est une victoire si évidente que beaucoup n'y verraient pas beaucoup de valeur, mais cela en vaudra la peine :). Rendre le monde un peu plus sain.

Concernant IsActive étant un booléen. Je suppose que vous envisagez d'en faire un BIT champ. C'est peut-être la voie à suivre, mais il est parfois préférable d'utiliser TINYINT car il y a la possibilité d'étendre le sens à plus de 2 états. Dans ce cas, il devient vraiment plus de StatusID . Habituellement, il s'agit de quelque chose qui commence de manière simpliste en tant qu'actif / Inactif , mais plus tard peut-être Supprimé et/ou autres. Du point de vue du dimensionnement, TINYINT est toujours de 1 octet. En revanche, BIT est de 1 octet pour un maximum de 8 BIT champs . Autrement dit, un BIT le champ est de 1 octet, 2 BIT champs est également d'un octet, et ainsi de suite jusqu'à 8 BIT les champs étant stockés dans un seul octet. Donc, il n'y a pas d'économie d'espace en choisissant BIT sur TINYINT lorsque la table n'a qu'un seul BIT champ. Juste quelque chose à considérer.

Faire un ALTER TABLE est un peu trop pour une grande table, comme vous l'avez vu. Une option, bien que pas géniale, consiste à ajouter un NOT NULL champ--Number_1new --avec un DEFAULT valeur (ce sera instantané en raison de la valeur par défaut, au moins à partir de SQL 2012) qu'aucun d'entre eux n'aurait naturellement (par exemple 255), puis migrer lentement les valeurs, dans une boucle, comme dans :

UPDATE TOP (5000) tab
SET tab.Number_1new = tab.Number_1
FROM [table] tab
WHERE tab.Number_1new = 255;

Et quand c'est fait, faites :

sp_rename 'table.Number_1', 'Number_1old', 'COLUMN';
sp_rename 'table.Number_1new', 'Number_1', 'COLUMN';

Bien sûr, mieux vaut envelopper cela dans une TRANSACTION, et cela dans un TRY / CATCH. Lorsque le code associé a été mis à jour et que tout a été testé et que les données semblent bonnes, vous pouvez supprimer le Number_1old colonne.

Cependant, la meilleure façon que j'ai trouvée est de créer une nouvelle table, de transférer lentement les données, puis d'échanger les tables et le code en même temps. J'ai détaillé les étapes dans un article sur SQL Server Central :Restructurer 100 millions de lignes (ou plus) Tables en quelques secondes. SRSLY ! (inscription gratuite obligatoire). Au cas où vous auriez des problèmes pour accéder à cet article, voici les étapes de base :

  1. Créez une nouvelle table avec la structure idéale--[tableNew]. Si vous êtes sur Enterprise Edition, envisagez d'activer la compression ROW ou PAGE car ils peuvent parfois aider. Mais s'il vous plaît faites d'abord des recherches car il y a des situations où ils ont un effet négatif. Il existe une documentation sur MSDN pour vous aider à le comprendre ainsi que des outils pour vous aider à estimer les économies potentielles. Mais même si vous activez la compression, je ne verrais pas cette action comme remplaçant le projet que vous faites ici.
  2. Ajouter un déclencheur AFTER UPDATE, DELETE sur [table] pour synchroniser les modifications (mais pas besoin de s'inquiéter des nouvelles lignes)
  3. Créez une tâche d'agent SQL qui se déplace sur les lignes manquantes par lots. Faites ceci dans une boucle qui fait un INSERT INTO [tableNew] (Columns) SELECT TOP (n) Columns FROM [table] WHERE ?? ORDER BY ??
  4. Les clauses WHERE et ORDER BY dépendent de la situation. Ils devraient viser à tirer le meilleur parti de l'index clusterisé. Si l'index clusterisé de la nouvelle table est structurellement le même que l'ancienne/actuelle table, alors au début de chaque boucle, vous pouvez obtenir le MAX([id]) de [tableNew] et l'utiliser pour obtenir WHERE table.[id] > @MaxIdInTableNew ORDER BY table.[id] .
  5. Créez la nouvelle table, déclenchez sur la table actuelle et le travail de l'agent SQL environ une semaine avant de devoir effectuer le basculement complet. Ce délai peut changer en fonction de votre situation, mais assurez-vous simplement de vous donner suffisamment de temps. Il est de loin préférable que le travail termine la migration des lignes et n'en ait que quelques-unes à la fois plutôt que d'être à 100 000 de l'ensemble complet lorsque la version est censée commencer.
  6. Si le plan est de migrer les autres tables associées (les références PK pour les deux FK que vous souhaitez transformer en INT s), puis créez ces champs ici INT maintenant et n'ajoutez pas le FK jusqu'à ce que ces autres tables soient migrées pour avoir des champs INT comme PK. Vous ne voulez pas avoir à recréer cette table juste pour apporter cette modification aux champs FK.
  7. Pendant le cut-over (dans un TRY/CATCH, bien sûr) :
    1. COMMENCER TRAN
    2. faire un décompte final des lignes sur les deux tables pour s'assurer que tout est déplacé (vous voudrez peut-être vérifier l'intégrité des lignes avant la publication pour vous assurer que le déclencheur a effectué les mises à jour et les suppressions comme prévu)
    3. renommer la table actuelle en "ancienne"
    4. renommer le "nouveau" tableau pour ne pas avoir le "nouveau"
    5. supprimer le travail de l'Agent SQL (ou au moins le désactiver)
    6. renommer et objets dépendants tels que contraintes, etc
    7. COMMITTER