J'ai trouvé plusieurs sources qui indiquent ALTER TABLE ... DROP COLUMN est une opération de métadonnées uniquement.
Comment se peut-il? Les données pendant une DROP COLUMN n'ont-elles pas besoin d'être purgées des index non groupés sous-jacents et des index / tas cluster?
De plus, pourquoi les documents Microsoft impliquent-ils qu'il s'agit d'une opération entièrement journalisée?
Les modifications apportées à la table sont enregistrées et entièrement récupérables. Les modifications qui affectent toutes les lignes des grandes tables, telles que la suppression d'une colonne ou, sur certaines éditions de SQL Server, l'ajout d'une colonne NOT NULL avec une valeur par défaut, peuvent prendre beaucoup de temps pour se terminer et générer de nombreux enregistrements de journal . Exécutez ces instructions ALTER TABLE avec le même soin que toute instruction INSERT, UPDATE ou DELETE qui affecte de nombreuses lignes.
Comme question secondaire: comment le moteur garde-t-il les colonnes supprimées si les données ne sont pas supprimées des pages sous-jacentes?
la source
Réponses:
Dans certaines circonstances, la suppression d'une colonne peut être une opération de métadonnées uniquement. Les définitions de colonne pour une table donnée ne sont pas incluses dans chaque page où les lignes sont stockées, les définitions de colonne ne sont stockées que dans les métadonnées de la base de données, y compris sys.sysrowsets, sys.sysrscols, etc.
Lors de la suppression d'une colonne qui n'est référencée par aucun autre objet, le moteur de stockage marque simplement la définition de la colonne comme n'étant plus présente en supprimant les détails pertinents de diverses tables système. L'action de supprimer les métadonnées invalide le cache de procédure, ce qui nécessite une recompilation chaque fois qu'une requête référence ultérieurement cette table. Étant donné que la recompilation renvoie uniquement les colonnes qui existent actuellement dans la table, les détails de la colonne pour la colonne supprimée ne sont même jamais demandés; le moteur de stockage ignore les octets stockés dans chaque page pour cette colonne, comme si la colonne n'existe plus.
Lorsqu'une opération DML suivante se produit sur la table, les pages concernées sont réécrites sans les données de la colonne supprimée. Si vous reconstruisez un index cluster ou un segment de mémoire, tous les octets de la colonne supprimée ne sont naturellement pas réécrits sur la page sur le disque. Cela répartit efficacement la charge de chute de la colonne au fil du temps, ce qui la rend moins perceptible.
Dans certaines circonstances, vous ne pouvez pas supprimer une colonne, par exemple lorsque la colonne est incluse dans un index ou lorsque vous avez créé manuellement un objet de statistiques pour la colonne. J'ai écrit un article de blog montrant l'erreur qui se présente lors d'une tentative de modification d'une colonne avec un objet de statistiques créé manuellement. La même sémantique s'applique lors de la suppression d'une colonne - si la colonne est référencée par un autre objet, elle ne peut pas simplement être supprimée. L'objet de référence doit d'abord être modifié, puis la colonne peut être supprimée.
C'est assez facile à montrer en regardant le contenu du journal des transactions après avoir supprimé une colonne. Le code ci-dessous crée une table avec une seule colonne de 8 000 caractères longs. Il ajoute une ligne, puis la supprime et affiche le contenu du journal des transactions applicable à l'opération de suppression. Les enregistrements du journal montrent les modifications apportées aux différentes tables système où les définitions de table et de colonne sont stockées. Si les données de colonne étaient réellement supprimées des pages allouées à la table, vous verriez des enregistrements de journal enregistrant les données de page réelles; il n'y a pas de tels enregistrements.
(La sortie est trop grande pour être affichée ici, et dbfiddle.uk ne me permettra pas d'accéder à fn_dblog)
Le premier ensemble de sorties affiche le journal suite à la suppression de la colonne par l'instruction DDL. Le deuxième ensemble de sorties affiche le journal après l'exécution de l'instruction DML où nous mettons à jour la
rid
colonne. Dans le deuxième jeu de résultats, nous voyons des enregistrements de journal indiquant une suppression par rapport à dbo.DropColumnTest, suivie d'une insertion dans dbo.DropColumnTest. Chaque longueur d'enregistrement de journal est 8116, indiquant que la page réelle a été mise à jour.Comme vous pouvez le voir sur la sortie de la
fn_dblog
commande dans le test ci-dessus, toute l'opération est entièrement enregistrée. Cela vaut pour une récupération simple, ainsi qu'une récupération complète. La terminologie «entièrement enregistré» peut être mal interprétée car la modification des données n'est pas enregistrée. Ce n'est pas ce qui se passe - la modification est enregistrée et peut être entièrement annulée. Le journal n'enregistre simplement que les pages qui ont été touchées, et comme aucune des pages de données de la table n'a été enregistrée par l'opération DDL, laDROP COLUMN
et toute annulation qui peut se produire se produiront extrêmement rapidement, quelle que soit la taille de la table.Pour la science , le code suivant videra les pages de données du tableau inclus dans le code ci-dessus, en utilisant le
DBCC PAGE
style "3". Le style "3" indique que nous voulons l'en- tête de page plus une interprétation détaillée par ligne . Le code utilise un curseur pour afficher les détails de chaque page du tableau, vous pouvez donc vous assurer de ne pas l'exécuter sur un grand tableau.En regardant la sortie de la première page de ma démo (après la suppression de la colonne, mais avant la mise à jour de la colonne), je vois ceci:
J'ai supprimé la plupart du vidage de page brut de la sortie ci-dessus pour plus de brièveté. À la fin de la sortie, vous verrez ceci pour la
rid
colonne:La dernière ligne ci-dessus
rid = 1
,, renvoie le nom de la colonne et la valeur actuelle stockée dans la colonne de la page.Ensuite, vous verrez ceci:
La sortie montre que l'emplacement 0 contient une colonne supprimée, en vertu du
DELETED
texte où le nom de la colonne serait normalement. La valeur de la colonne est renvoyéeNULL
car la colonne a été supprimée. Cependant, comme vous pouvez le voir dans les données brutes, la valeur longue de 8 000 caractèresREPLICATE('Z', 8000)
, pour cette colonne existe toujours sur la page. Voici un exemple de cette partie de la sortie DBCC PAGE:la source