Database
 sql >> Datenbank >  >> RDS >> Database

Der Mythos, dass DROP und TRUNCATE TABLE nicht protokolliert werden

Es gibt einen hartnäckigen Mythos in der SQL Server-Welt, dass sowohl die DROP TABLE und TRUNCATE TABLE Befehle werden nicht protokolliert.

Sie sind nicht. Sie sind beide vollständig protokolliert, aber effizient protokolliert.

Das können Sie sich leicht selbst beweisen. Führen Sie den folgenden Code aus, um eine Testdatenbank und -tabelle einzurichten, und zeigen Sie, dass unsere Tabelle 10.000 Zeilen enthält:

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

Ergebnisse:

Zeilenanzahl
———–
10000

Und dann der folgende Code, der die Tabelle in einer Transaktion abschneidet und die Zeilenanzahl überprüft:

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

Ergebnisse:

Zeilenanzahl
———–
0

Jetzt ist der Tisch leer. Aber ich kann die Transaktion rückgängig machen und alle Daten wieder zurücksetzen:

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

Ergebnisse:

Zeilenanzahl
———–
10000

Ganz klar das TRUNCATE Der Vorgang muss protokolliert werden, sonst würde der Rollback-Vorgang nicht funktionieren.

Woher kommt also das Missverständnis?

Es kommt vom Verhalten von DROP und TRUNCATE Operationen auf großen Tabellen. Sie werden fast sofort abgeschlossen, und wenn Sie mit fn_dblog in das Transaktionsprotokoll schauen Unmittelbar danach sehen Sie nur eine kleine Anzahl von Protokolleinträgen, die aus der Operation generiert wurden. Diese kleine Zahl korreliert nicht mit der Größe der Tabelle, die abgeschnitten oder gelöscht wird, also scheint es, als ob DROP und TRUNCATE Vorgänge werden nicht protokolliert.

Aber sie sind vollständig protokolliert, wie ich oben gezeigt habe. Wo sind also die Protokolldatensätze für die Vorgänge?

Die Antwort lautet, dass die Protokolldatensätze, wenn auch nicht sofort, durch einen Mechanismus namens „deferred drop“ erstellt werden, der in SQL Server 2000 SP3 hinzugefügt wurde.

Wenn eine Tabelle gelöscht oder abgeschnitten wird, müssen alle Datendateiseiten, die der Tabelle zugeordnet sind, freigegeben werden. Der Mechanismus dafür war vor SQL Server 2000 SP3 wie folgt:

Für jeden Extent, der der Tabelle zugeordnet ist

Beginnen Sie

Erwerben Sie eine exklusive Zuordnungssperre für den Extent



Prüfen Sie die Seitensperre für jede Seite im Extent (Erwerben Sie die Sperre im eXclusive-Modus und heben Sie sie sofort auf, um sicherzustellen, dass niemand sonst die Seite gesperrt hat)



NICHT Heben Sie die Extent-Sperre auf, um sicherzustellen, dass niemand anderes diesen Extent verwenden kann



Zum nächsten Extent wechseln

Ende

Da alle Extent-Sperren bis zum Ende der Operation gehalten wurden und jede Sperre eine kleine Menge Speicher beansprucht, war es möglich, dass dem Sperren-Manager bei einem DROP der Speicher ausging oder TRUNCATE einer sehr großen Tabelle aufgetreten. Einige SQL Server-Kunden stellten fest, dass sie auf SQL Server 2000 auf Speichermangel stießen, da die Tabellen sehr groß wurden und das Wachstum des Systemspeichers bei weitem übertrafen.

Der Deferred-Drop-Mechanismus simuliert den DROP oder TRUNCATE Der Vorgang wird sofort abgeschlossen, indem die Zuweisungen für die Tabelle entkoppelt und in die „Deferred-Drop-Warteschlange“ gestellt werden, damit sie später von einer Hintergrundaufgabe verarbeitet werden können. Dieser Unhook-and-Transfer-Vorgang generiert nur eine Handvoll Protokolldatensätze. Dies ist die Operation, die in meinem obigen Codebeispiel ausgeführt und zurückgesetzt wird.
Die 'Deferred-Drop-Hintergrundtask' wird alle paar Sekunden hochgefahren und hebt alle Seiten und Extents in der Deferred-Drop-Warteschlange klein auf Batches, wodurch sichergestellt wird, dass dem Vorgang nicht der Arbeitsspeicher ausgeht. Diese Freigaben werden alle vollständig protokolliert, aber denken Sie daran, dass die Freigabe einer Seite voller Daten- oder Indexdatensätze keine einzelnen Löschungen dieser Datensätze protokolliert; stattdessen wird die gesamte Seite in der relevanten PFS-Zuweisungs-Bytemap (Page Free Space) einfach als freigegeben markiert.

Ab SQL Server 2000 SP3, wenn Sie einen DROP ausführen oder TRUNCATE einer Tabelle sehen Sie nur wenige Protokolldatensätze, die generiert werden. Wenn Sie etwa eine Minute warten und dann erneut in das Transaktionsprotokoll schauen, werden Sie sehen, dass Tausende von Protokolldatensätzen durch die Deferred-Drop-Operation generiert wurden, die jeweils eine Seite oder einen Extent freigeben. Der Vorgang wird vollständig und effizient protokolliert.

Hier ist ein Beispiel, das das oben erstellte Szenario verwendet:

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

Ergebnisse:

LogRecCount

———–

25

Wie Sie sehen können, gibt es eindeutig keine Protokolleinträge, die die 10.000 Seiten plus 1.250 Extents in der TestTable-Tabelle aufheben.

Wenn ich ein paar Sekunden warte und dann fn_dblog ausführe Code erneut, ich bekomme:

LogRecCount

———–

3811

Sie fragen sich vielleicht, warum es nicht mindestens 10.000 Protokolleinträge gibt – einen für jede Seite, deren Zuordnung aufgehoben wird. Das liegt daran, dass die Seitenfreigaben sogar effizient protokolliert werden – mit einem Protokolldatensatz, der die Änderungen der PFS-Seitenzuordnung für 8 aufeinanderfolgende Datendateiseiten widerspiegelt, anstatt eines Protokolldatensatzes für jede Datendateiseite, der die Änderung des Zuordnungsstatus auf der PFS-Seite widerspiegelt.

SQL Server versucht immer, so wenig Transaktionsprotokoll wie möglich zu erstellen, während die Regeln zur vollständigen oder minimalen Protokollierung auf der Grundlage des aktuellen Wiederherstellungsmodells eingehalten werden. Wenn Sie sich die tatsächlichen Protokolldatensätze ansehen möchten, die von den Unhook-and-Transfer- und Deferred-Drop-Mechanismen generiert werden, ersetzen Sie einfach * für COUNT (*) im obigen fn_dblog-Code und suchen Sie nach einer Transaktion, deren Transaktionsname auf DeferredAllocUnitDrop::Process .

In zukünftigen Beiträgen werde ich die Interna besprechen, die andere hartnäckige Mythen rund um Leistungsaspekte der SQL Server-Speicher-Engine untermauern.