sql >> Database >  >> RDS >> Database

De mythe dat DROP en TRUNCATE TABLE niet gelogd zijn

Er is een hardnekkige mythe in de SQL Server-wereld dat zowel de DROP TABLE en TRUNCATE TABLE commando's zijn niet gelogd.

Zij zijn niet. Ze zijn allebei volledig gelogd, maar efficiënt gelogd.

Dit kun je jezelf gemakkelijk bewijzen. Voer de volgende code uit om een ​​testdatabase en -tabel in te stellen en laat zien dat we 10.000 rijen in onze tabel hebben:

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

Resultaten:

RowCount
———–
10000

En dan de volgende code, die de tabel in een transactie afkapt en het aantal rijen controleert:

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

Resultaten:

RowCount
———–
0

Nu is de tafel leeg. Maar ik kan de transactie terugdraaien en alle gegevens weer terugzetten:

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

Resultaten:

RowCount
———–
10000

Duidelijk de TRUNCATE bewerking moet worden vastgelegd, anders zou de terugdraaibewerking niet werken.

Dus waar komt de misvatting vandaan?

Het komt van het gedrag van DROP en TRUNCATE bewerkingen op grote tafels. Ze worden bijna onmiddellijk voltooid en als u in het transactielogboek kijkt met fn_dblog direct daarna ziet u slechts een klein aantal logboekrecords die door de bewerking zijn gegenereerd. Dat kleine aantal correleert niet met de grootte van de tabel die wordt afgekapt of verwijderd, dus het lijkt alsof DROP en TRUNCATE bewerkingen worden niet gelogd.

Maar ze zijn volledig geregistreerd, zoals ik hierboven heb aangetoond. Dus waar zijn de logrecords voor de operaties?

Het antwoord is dat de logboekrecords worden gemaakt, alleen niet onmiddellijk, door een mechanisme genaamd 'uitgestelde drop', dat is toegevoegd in SQL Server 2000 SP3.

Wanneer een tabel wordt verwijderd of afgekapt, moeten alle gegevensbestandspagina's die aan de tabel zijn toegewezen, worden verwijderd. Het mechanisme hiervoor vóór SQL Server 2000 SP3 was als volgt:

Voor elke omvang die aan de tafel is toegewezen

Begin

Verkrijg een exclusieve toewijzingsvergrendeling op de omvang



Onderzoek de paginavergrendeling voor elke pagina in de mate (verkrijg de vergrendeling in de exclusieve modus en laat deze onmiddellijk vallen, zorg ervoor dat niemand anders de pagina vergrendeld heeft)



NIET ontgrendel de extensie, zodat niemand anders die extensie kan gebruiken



Ga naar de volgende extensie

Einde

Aangezien alle vergrendelingen werden vastgehouden tot het einde van de operatie, en elke vergrendeling een kleine hoeveelheid geheugen in beslag neemt, was het mogelijk dat de vergrendelingsbeheerder onvoldoende geheugen had wanneer een DROP of TRUNCATE van een zeer grote tafel plaatsvond. Sommige SQL Server-klanten begonnen te ontdekken dat ze onvoldoende geheugen hadden op SQL Server 2000, omdat tabellen erg groot werden en de groei van het systeemgeheugen enorm overtroffen.

Het uitgestelde-dropmechanisme simuleert de DROP of TRUNCATE bewerking onmiddellijk voltooien, door de toewijzingen voor de tafel los te koppelen en in de 'uitgestelde-drop-wachtrij' te plaatsen, voor latere verwerking door een achtergrondtaak. Deze onthaak-en-overdrachtsbewerking genereert slechts een handvol logrecords. Dit is de bewerking die wordt uitgevoerd en teruggedraaid in mijn codevoorbeeld hierboven.
De 'deferred-drop background task' start om de paar seconden op en heft alle pagina's en delen in de uitgestelde-drop-wachtrij op in kleine batches, zodat de bewerking niet zonder geheugen komt te zitten. Deze deallocaties zijn allemaal volledig gelogd, maar onthoud dat het vrijgeven van een pagina vol gegevens of indexrecords geen individuele verwijderingen van die records registreert; in plaats daarvan wordt de hele pagina gemarkeerd als niet meer toegewezen in de relevante PFS (Page Free Space)-toewijzingsbytemap.

Vanaf SQL Server 2000 SP3, wanneer u een DROP . uitvoert of TRUNCATE van een tabel ziet u slechts enkele logrecords die worden gegenereerd. Als u een minuut of zo wacht en vervolgens opnieuw in het transactielogboek kijkt, ziet u dat duizenden logboekrecords zijn gegenereerd door de uitgestelde-drop-bewerking, waarbij elk een pagina of een gebied ongedaan maakt. De operatie wordt volledig en efficiënt gelogd.

Hier is een voorbeeld, gebruikmakend van het scenario dat we hierboven hebben gemaakt:

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

Resultaten:

LogRecCount

———–

25

Zoals u kunt zien, zijn er duidelijk geen logboekrecords die de toewijzing van de 10.000 pagina's plus 1250 extensies in de TestTable-tabel ongedaan maken.

Als ik een paar seconden wacht en dan de fn_dblog . uitvoer code opnieuw, krijg ik:

LogRecCount

———–

3811

Je vraagt ​​je misschien af ​​waarom er niet minstens 10.000 logrecords zijn - één voor elke pagina die wordt verwijderd. Dat komt omdat de paginadeallocaties zelfs efficiënt worden gelogd - met één logrecord dat de PFS-paginatoewijzingswijzigingen voor 8 opeenvolgende gegevensbestandspagina's weergeeft, in plaats van één logrecord voor elke gegevensbestandspagina die de toewijzingsstatus weergeeft die op de PFS-pagina verandert.

SQL Server probeert altijd zo min mogelijk transactielogboeken te produceren, maar houdt zich toch aan de regels over volledige of minimale logboekregistratie op basis van het huidige herstelmodel. Als u de daadwerkelijke logrecords wilt bekijken die zijn gegenereerd door de onthaak-en-overdracht en uitgestelde-drop-mechanismen, vervangt u gewoon * door COUNT (*) in de fn_dblog-code hierboven en zoekt u naar een transactie met de transactienaam ingesteld op DeferredAllocUnitDrop::Process .

In toekomstige berichten zal ik de interne aspecten bespreken die ten grondslag liggen aan andere hardnekkige mythes rond prestatieaspecten van de SQL Server Storage Engine.


  1. Select-resultaten converteren naar invoegscript - SQL Server

  2. MySQL-replicatie en op GTID gebaseerde failover - een diepe duik in foutieve transacties

  3. Hoe krijg ik de grenscoördinaten voor een Amerikaanse postcode?

  4. MySQL - Een kolom selecteren die niet in Group By is