SQL Server "leere Tabelle" ist langsam nach dem Löschen aller (12 Millionen) Datensätze?


27

Ich habe eine SQL Server 2008-Instanz mit ungefähr 150 Spalten. Ich habe diese Tabelle zuvor mit ungefähr 12 Millionen Einträgen gefüllt, die Tabelle jedoch in Vorbereitung auf einen neuen Datensatz geleert.

Befehle, die einst auf einer leeren Tabelle wie count(*)und select top 1000in ausgeführt wurden SQL Management Studio, benötigen jetzt jedoch eine Ewigkeit.

SELECT COUNT(*) FROM TABLE_NAME 

Es dauerte über 11 Minuten, um 0 zurückzugeben, und SELECT TOP 1000fast 10 Minuten, um einen leeren Tisch zurückzugeben.

Mir ist auch aufgefallen, dass der freie Speicherplatz auf meiner Festplatte buchstäblich verschwunden ist (von ca. 100G auf 20G). Das einzige, was dazwischen passierte, war eine einzelne Abfrage, die ich ausgeführt habe:

DELETE FROM TABLE_NAME

Was in aller Welt ist los?!?


5
Welches Wiederherstellungsmodell verwendet Ihre Datenbank? Wenn es "Voll" ist, speichert Ihre SQL-Instanz eine Aufzeichnung aller dieser Löschvorgänge. Dies könnte der Ort sein, an dem sich Ihr freier Speicherplatz befand. Wenn eine vollständige Wiederherstellung erforderlich ist, empfehle ich die Verwendung von TRUNCATE TABLEanstelle von DELETE FROM.
Tullo_x86

2
150 Spalten? Diese Tabelle ist möglicherweise überfüllt - die meisten Tupel sollten viel kleiner sein. Ohne vollständigen Kontext jedoch nicht zu sagen.
Clockwork-Muse

Antworten:


42

Es wurde dir bereits gesagt, warum TRUNCATEes so viel schneller / besser / sexyer wäre als DELETE, aber es bleibt noch eine Frage zu beantworten:

Warum ist es SELECTnach DELETE Abschluss langsamer ?

Das liegt daran, dass DELETEnur die Zeilen gespenst hat . Die Tabelle ist genauso groß wie bei 12 Millionen Zeilen, obwohl es keine gibt. Das Zählen der Zeilen (0) dauert genauso lange wie das Zählen von 12 Millionen Zeilen. Mit der Zeit sammelt der Bereinigungsprozess von Geistern diese Geisterdatensätze und hebt die Zuordnung von Seiten auf, die nur Geister enthalten, und Ihre SELECT-Vorgänge werden beschleunigt. Aber gerade jetzt, wenn Sie einchecken Skipped Ghosted Records/secPerfmon ist wahrscheinlich explodiert während SELECT COUNT(*). Sie könnten auch die Dinge beschleunigen , indem die Tabelle wieder aufzubauen: ALTER TABLE ... REBUILD.

TRUNCATE hätte mich auch um dieses problem gekümmert, da es keine geister hinterlässt.

Siehe auch In der Storage Engine: Ghost-Bereinigung in der Tiefe .


13

DELETEAnweisungen löschen Zeilen nacheinander aus einer Tabelle, protokollieren jede Zeile in der transaction logund pflegen log sequence number (LSN)Informationen. Da Sie bereits erwähnt haben, dass Ihre Tabelle riesige Daten enthält (12 Millionen Datensätze), überprüfen Sie nach dem Löschen, ob auf Ihrer Festplatte nicht mehr genügend Speicherplatz vorhanden ist, die Größe Ihrer Datenbankprotokolldatei. Es wäre höchstwahrscheinlich gewachsen.

Ein besserer Weg wäre gewesen:

TRUNCATE TABLE_NAME

2
+1, genau das gleiche gilt für Oracle DB. Wenn Sie Anweisungen verwenden, durch die Datensätze protokolliert werden, wird die Datenbank mit der Zeit langsamer.
Petro Semeniuk

@PetroSemeniuk Nach dem, was ich bei Oracle erinnere, lässt das Löschen die Hochwassermarke allein, das Abschneiden setzt die Hochwassermarke zurück. Ich glaube, dass alle Operationen, die einen vollständigen Scan erfordern, die Blöcke bis zur Hochwassermarke scannen. Das Löschen kann daher bei indizierten Operationen hilfreich sein, nicht jedoch bei Scans. TRUNCATE war die richtige Operation.
Glenn

3

(Dies war ursprünglich ein Kommentar zu @ DaveEs Antwort, aber ich habe ihn in eine eigene Antwort eingefügt, weil er lang wurde.)

TRUNCATE ist eine protokollierte Operation. Es muss ansonsten nicht ACID-konform sein. Unterschiede zwischen TRUNCATEund DELETE:

  • Nutzung des TRUNCATEProtokollspeicherplatzes : Protokolliert nur die freigegebenen Seiten / Bereiche *, während DELETEeinzelne Zeilen protokolliert werden.
  • TRUNCATEVerwendung von Sperren : Im Allgemeinen werden weniger Sperren verwendet, da eine Tabellensperre und Seitensperren erforderlich sind, im Gegensatz zu DELETEZeilensperren **.
  • IDENTITYsequence: TRUNCATESetzt die Identitätssequenz für eine Tabelle zurück, falls vorhanden.

(* Ein Extent = 8 Seiten TRUNCATEprotokolliert / entfernt Extents, wenn sie alle aus dieser einen Tabelle stammen, andernfalls werden Seiten aus gemischten Extents protokolliert / entfernt.

** Ein Nebeneffekt davon ist , dass DELETE FROM TABLEmöglicherweise leere Seiten der Tabelle zugeordnet werden kann, je nachdem , ob die Operation eine exklusive Tabellensperre bekommen kann oder nicht.)

Dies ist (zurück zur ursprünglichen Frage) eindeutig TRUNCATE TABLEbesser, als DELETE FROM TABLEwenn Sie die Tabelle leeren, aber die Struktur beibehalten möchten ( TRUNCATEHinweis : Kann nicht für eine Tabelle verwendet werden, auf die ein Fremdschlüssel aus einer anderen Tabelle verweist).

Überprüfen Sie, wie in @ Tullos Kommentar erwähnt, auch das Wiederherstellungsmodell Ihrer Datenbank. Wenn es voll ist, müssen Sie entweder mit dem Erstellen von Protokollsicherungen beginnen oder Ihr Wiederherstellungsmodell in "Einfach" ändern. Sobald Sie eine dieser beiden getan haben, werden Sie wahrscheinlich wollen Ihre Log - Datei schrumpfen als einmalige Operation (NB: Protokolldatei nur ), um alle , dass der freie Raum zurückzufordern.

Zum Schluss noch etwas zu beachten - Tabellenstatistik. Führen Sie UPDATE STATISTICS <TABLENAME>' afterTRUNCATE /DELETE` aus, damit das Abfrageoptimierungsprogramm nicht durch alte Statistiken gestört wird.


2

(HINWEIS: Ich bin kein DBA.) DELETE ist eine protokollierte Operation und gibt den verwendeten Speicherplatz nicht frei. Sie haben wahrscheinlich ein großes Transaktionsprotokoll, das Speicherplatz belegt und Tabellen-Scans auf dem 'leeren' Tabellenbereich ausführt. Ich schätze, Sie müssen das Transaktionsprotokoll löschen und Ihre Datenbank verkleinern. Dieser StackOverflow-Artikel soll Ihnen den Einstieg erleichtern .

Verwenden Sie TRUNCATE TABLE, wenn Sie dies in Zukunft tun möchten.

EDIT: Meine Aussage über TRUNCATE nicht protokolliert wurde, war fehlerhaft. entfernt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.