sql >> Database teknologi >  >> RDS >> Database

Myten om, at DROP og TRUNCATE TABLE er ikke-loggede

Der er en vedvarende myte i SQL Server-verdenen, at både DROP TABLE og TRUNCATE TABLE kommandoer er ikke-loggede.

Det er de ikke. De er begge fuldt logget, men effektivt logget.

Det kan du nemt bevise for dig selv. Kør følgende kode for at opsætte en testdatabase og -tabel, og vis, at vi har 10.000 rækker i vores tabel:

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

Resultater:

Rækketælling
———–
10000

Og derefter følgende kode, som afkorter tabellen i en transaktion og kontrollerer rækkeantallet:

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

Resultater:

Rækketælling
———–
0

Nu er bordet tomt. Men jeg kan rulle transaktionen tilbage og sætte alle data tilbage igen:

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

Resultater:

Rækketælling
———–
10000

Tydeligt TRUNCATE operation skal logges, ellers ville roll back operationen ikke fungere.

Så hvor kommer misforståelsen fra?

Det kommer fra adfærden hos DROP og TRUNCATE operationer på store borde. De vil fuldføre næsten øjeblikkeligt, og hvis du ser i transaktionsloggen ved hjælp af fn_dblog lige bagefter vil du kun se et lille antal logposter genereret fra operationen. Det lille tal korrelerer ikke med størrelsen på den tabel, der afkortes eller slettes, så det ser ud som om DROP og TRUNCATE operationer er ikke-loggede.

Men de er fuldt logget, som jeg viste ovenfor. Så hvor er logposterne for operationerne?

Svaret er, at logposterne vil blive oprettet, bare ikke med det samme, af en mekanisme kaldet 'deferred drop', som blev tilføjet i SQL Server 2000 SP3.

Når en tabel slettes eller afkortes, skal alle de datafilsider, der er allokeret til tabellen, deallokeres. Mekanismen for dette før SQL Server 2000 SP3 var som følger:

For hvert omfang, der er allokeret til tabellen

Begynd

Anskaf en eksklusiv tildelingslås på omfanget



Undersøg sidelås for hver side i omfanget (hent låsen i eksklusiv tilstand, og slip den straks, og sørg for, at ingen andre har siden låst)



IKKE frigør omfangslåsen, hvilket garanterer, at ingen andre kan bruge det omfang



Flyt til næste omfang

Slut

Da alle låsene blev holdt indtil slutningen af ​​operationen, og hver lås tager en lille mængde hukommelse, var det muligt for låseadministratoren at løbe tør for hukommelse, når en DROP eller TRUNCATE af et meget stort bord opstod. Nogle SQL Server-kunder begyndte at finde ud af, at de løb ind i tilstande, der ikke var mere hukommelse på SQL Server 2000, da tabeller blev meget store og langt oversteg væksten i systemhukommelsen.

Den deferred-drop-mekanisme simulerer DROP eller TRUNCATE operation afsluttes med det samme, ved at løsne allokeringerne til bordet og sætte dem i 'udskudt-drop-køen' til senere behandling af en baggrundsopgave. Denne afhægt-og-overførsel-operation genererer kun en håndfuld logposter. Dette er den handling, der bliver udført og rullet tilbage i mit kodeeksempel ovenfor.
Baggrundsopgaven med udskudt fald" snurrer op med få sekunders mellemrum og deallokerer alle sider og omfang i køen med udskudt aflevering i små batches, hvilket garanterer, at operationen ikke løber tør for hukommelse. Disse deallokeringer er alle fuldt logget, men husk, at deallokering af en side fuld af data eller indeksposter ikke logger individuelle sletninger af disse poster; i stedet er hele siden bare markeret som deallokeret i den relevante PFS (Page Free Space) allokering byte-map.

Fra SQL Server 2000 SP3 og fremefter, når du udfører en DROP eller TRUNCATE af en tabel, vil du kun se nogle få logposter, der bliver genereret. Hvis du venter et minut eller deromkring, og derefter kigger i transaktionsloggen igen, vil du se, at tusindvis af logposter er blevet genereret af den udskudte drop-operation, som hver deallokerer en side eller et omfang. Operationen logges fuldt ud og effektivt.

Her er et eksempel ved hjælp af scenariet, vi oprettede ovenfor:

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

Resultater:

LogRecCount

———–

25

Som du kan se, er der tydeligvis ikke logposter, der deallokerer de 10.000 sider plus 1.250 omfang i testtabellen.

Hvis jeg venter et par sekunder og derefter kører fn_dblog kode igen, jeg får:

LogRecCount

———–

3811

Du undrer dig måske over, hvorfor der ikke er mindst 10.000 logposter - en for hver side, der deallokeres. Det skyldes, at sidetildelingerne endda logges effektivt – med én logpost, der afspejler PFS-sideallokeringsændringer for 8 på hinanden følgende datafilsider, i stedet for én logpost for hver datafilside, der afspejler dens tildelingsstatus, der ændres på PFS-siden.

SQL Server forsøger altid at producere så lidt transaktionslog som muligt, mens den stadig overholder reglerne om fuld eller minimal logning baseret på den aktuelle gendannelsesmodel. Hvis du ønsker at se på de faktiske logposter, der er genereret af unhook-and-transfer og deferred-drop-mekanismerne, skal du blot erstatte * med COUNT (*) i fn_dblog-koden ovenfor og se efter en transaktion med Transaktionsnavnet sat til DeferredAllocUnitDrop::Process .

I fremtidige indlæg vil jeg diskutere de interne elementer, der understøtter andre vedvarende myter omkring ydeevneaspekter af SQL Server Storage Engine.


  1. SQLite database læk fundet

  2. Arbejder med Salesforce.com i Alpha Anywhere

  3. Start af blogging til HTML5 og CSS3

  4. Automatisk forøgelse af 'id'-værdi ved indsættelse i sqlite