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

Le mythe selon lequel DROP et TRUNCATE TABLE ne sont pas enregistrés

Il existe un mythe persistant dans le monde SQL Server selon lequel à la fois DROP TABLE et TRUNCATE TABLE les commandes ne sont pas enregistrées.

Ils ne sont pas. Ils sont tous les deux entièrement connectés, mais efficacement.

Vous pouvez facilement vous le prouver. Exécutez le code suivant pour configurer une base de données et une table de test, et montrez que nous avons 10 000 lignes dans notre table :

CREATE DATABASE [TruncateTest];
GO
 
ALTER DATABASE [TruncateTest] SET RECOVERY SIMPLE;
GO
 
USE [TruncateTest];
GO
 
CREATE TABLE [TestTable] (
    [c1]    INT IDENTITY,
    [c2]    CHAR (8000) DEFAULT 'a');
GO
 
SET NOCOUNT ON;
GO
 
INSERT INTO [TestTable] DEFAULT VALUES;
GO 10000
 
SELECT
    COUNT (*) AS N'RowCount'
FROM
    [TestTable];
GO

Résultats :

RowCount
———–
10000

Et puis le code suivant, qui tronque la table dans une transaction et vérifie le nombre de lignes :

BEGIN TRAN;
GO
TRUNCATE TABLE [TestTable];
GO
 
SELECT
    COUNT (*) AS N'RowCount'
FROM
    [TestTable];
GO

Résultats :

RowCount
———–
0

Maintenant le tableau est vide. Mais je peux annuler la transaction et remettre toutes les données :

ROLLBACK TRAN;
GO
 
SELECT
    COUNT (*) AS N'RowCount'
FROM
    [TestTable];
GO

Résultats :

RowCount
———–
10000

Clairement le TRUNCATE l'opération doit être enregistrée sinon l'opération de restauration ne fonctionnerait pas.

Alors d'où vient cette idée fausse ?

Cela vient du comportement de DROP et TRUNCATE opérations sur de grandes tables. Ils se termineront presque instantanément, et si vous regardez dans le journal des transactions en utilisant fn_dblog juste après, vous ne verrez qu'un petit nombre d'enregistrements de journal générés à partir de l'opération. Ce petit nombre n'est pas en corrélation avec la taille de la table tronquée ou supprimée, il semble donc que DROP et TRUNCATE les opérations ne sont pas enregistrées.

Mais ils sont entièrement connectés, comme je l'ai démontré ci-dessus. Alors, où sont les enregistrements du journal des opérations ?

La réponse est que les enregistrements de journal seront créés, mais pas immédiatement, par un mécanisme appelé « suppression différée », qui a été ajouté dans SQL Server 2000 SP3.

Lorsqu'une table est supprimée ou tronquée, toutes les pages du fichier de données allouées à la table doivent être désallouées. Le mécanisme pour cela avant SQL Server 2000 SP3 était le suivant :

Pour chaque extent alloué à la table

Commencer

Acquérir un verrou d'allocation eXclusive sur l'extent



Sonder le verrouiller la page pour chaque page de l'étendue (acquérir le verrou en mode eXclusif et le supprimer immédiatement, en s'assurant que personne d'autre n'a verrouillé la page)



NE PAS libère le verrou d'étendue, garantissant que personne d'autre ne peut utiliser cette étendue



Passer à l'étendue suivante

Fin

Comme tous les verrous d'étendue étaient maintenus jusqu'à la fin de l'opération et que chaque verrou occupe une petite quantité de mémoire, il était possible que le gestionnaire de verrous manque de mémoire lorsqu'un DROP ou TRUNCATE d'une très grande table s'est produite. Certains clients SQL Server ont commencé à constater qu'ils rencontraient des problèmes de mémoire insuffisante sur SQL Server 2000, car les tables devenaient très volumineuses et dépassaient largement la croissance de la mémoire système.

Le mécanisme de dépôt différé simule le DROP ou TRUNCATE opération se terminant immédiatement, en décrochant les allocations pour la table et en les plaçant dans la "file d'attente de suppression différée", pour un traitement ultérieur par une tâche en arrière-plan. Cette opération de décrochage et de transfert ne génère qu'une poignée d'enregistrements de journal. C'est l'opération qui est effectuée et annulée dans mon exemple de code ci-dessus.
La "tâche d'arrière-plan de dépôt différé" tourne toutes les quelques secondes et libère toutes les pages et extensions de la file d'attente de dépôt différé en petits lots, garantissant que l'opération ne manquera pas de mémoire. Ces désallocations sont toutes entièrement consignées, mais rappelez-vous que la désallocation d'une page pleine de données ou d'enregistrements d'index ne consigne pas les suppressions individuelles de ces enregistrements ; au lieu de cela, la page entière est simplement marquée comme désallouée dans la carte d'octets d'allocation PFS (Page Free Space) appropriée.

À partir de SQL Server 2000 SP3, lorsque vous effectuez un DROP ou TRUNCATE d'une table, vous ne verrez que quelques enregistrements de journal générés. Si vous attendez environ une minute, puis regardez à nouveau dans le journal des transactions, vous verrez que des milliers d'enregistrements de journal ont été générés par l'opération de suppression différée, chacun désallouant une page ou une étendue. L'opération est entièrement et efficacement enregistrée.

Voici un exemple, utilisant le scénario que nous avons créé ci-dessus :

CHECKPOINT;
GO
TRUNCATE TABLE [TestTable];
GO
SELECT
    COUNT (*) AS N'LogRecCount'
FROM
    fn_dblog (NULL, NULL);
GO

Résultats :

LogRecCount

———–

25

Comme vous pouvez le voir, il n'y a clairement pas d'enregistrements de journal désallouant les 10 000 pages, plus 1 250 extensions dans la table TestTable.

Si j'attends quelques secondes, puis lance le fn_dblog code à nouveau, j'obtiens :

LogRecCount

———–

3811

Vous vous demandez peut-être pourquoi il n'y a pas au moins 10 000 enregistrements de journal - un pour chaque page désallouée. En effet, les désallocations de pages sont même enregistrées efficacement - avec un enregistrement de journal reflétant les changements d'allocation de page PFS pour 8 pages de fichier de données consécutives, au lieu d'un enregistrement de journal pour chaque page de fichier de données reflétant son statut d'allocation changeant dans la page PFS.

SQL Server essaie toujours de produire le moins de journaux de transactions possible, tout en respectant les règles de journalisation complète ou minimale en fonction du modèle de récupération actuel. Si vous souhaitez consulter les enregistrements de journal réels générés par les mécanismes de décrochage et de transfert et de suppression différée, remplacez simplement * par COUNT (*) dans le code fn_dblog ci-dessus et recherchez une transaction avec le nom de la transaction défini sur DeferredAllocUnitDrop::Process .

Dans les prochains articles, je discuterai des éléments internes qui sous-tendent d'autres mythes persistants concernant les aspects de performance du moteur de stockage SQL Server.