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, aber seitdem die Tabelle gelöscht, um einen neuen Datensatz vorzubereiten.
Befehle, die einmal sofort in einer leeren Tabelle ausgeführt wurden, wie z. B. count(*)
und select top 1000
im SQL Management Studio
Jetzt dauert es Äonen, um zu rennen.
SELECT COUNT(*) FROM TABLE_NAME
es dauerte über 11 Minuten, um 0 zurückzugeben, und SELECT TOP 1000
dauerte fast 10 Minuten, um einen leeren Tisch zurückzugeben.
Ich habe auch festgestellt, dass der freie Speicherplatz auf meiner Festplatte buchstäblich verschwunden ist (von etwa 100 G auf 20 G). Das einzige, was dazwischen passierte, war eine einzelne Abfrage, die ich ausgeführt habe:
DELETE FROM TABLE_NAME
Was in aller Welt ist los?!?
Sie haben bereits erfahren, warum TRUNCATE
so viel schneller/besser/sexier ist als DELETE
, aber es bleibt noch eine Frage zu beantworten:
SELECT
langsamer, nachdem DELETE
abgeschlossen ist ?Das liegt daran, dass DELETE
nur die Zeilen gespenstisch hat. Die Tabelle ist genauso groß wie bei 12 Millionen Zeilen, obwohl sie keine hat. Das Zählen der Zeilen (0) dauert genauso lange wie das Zählen von 12 Millionen Zeilen. Mit der Zeit wird der Ghost-Bereinigungsprozess diese Ghosted-Datensätze mit Müll sammeln und Seiten freigeben, die nur Ghosts enthalten, und Ihre SELECTs werden schneller. Aber gerade jetzt, wenn Sie Skipped Ghosted Records/sec
in perfmon überprüfen, explodiert wahrscheinlich während SELECT COUNT(*)
. Sie können die Dinge auch beschleunigen, indem Sie die Tabelle neu erstellen: ALTER TABLE ... REBUILD
.
TRUNCATE
hätte sich auch um dieses Problem gekümmert, da es keine Geister zurücklässt.
Siehe auch In der Storage Engine: Geisterbereinigung im Detail .
DELETE
-Anweisungen löschen nacheinander Zeilen aus einer Tabelle, protokollieren jede Zeile im transaction log
und pflegen log sequence number (LSN)
-Informationen. Da Sie erwähnt haben, dass Ihre Tabelle große Datenmengen enthält (12 Millionen Datensätze), überprüfen Sie nach dem Löschen, auf dem auf Ihrer Festplatte nicht 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
(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 sein, sonst ist es nicht ACID-konform. Unterschiede zwischen TRUNCATE
und DELETE
:
TRUNCATE
protokolliert nur freigegebene Seiten/Bereiche *, während DELETE
einzelne Zeilen protokolliert.TRUNCATE
verwendet im Allgemeinen weniger Sperren, da eine Tabellensperre und Seitensperren erforderlich sind, im Gegensatz zu DELETE
, das Zeilensperren verwendet **.IDENTITY
Sequenzen: TRUNCATE
setzt die Identitätssequenz für eine Tabelle zurück, falls vorhanden.(* Ein Extent = 8 Seiten. TRUNCATE
protokolliert/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 TABLE
kann möglicherweise leere Seiten der Tabelle zuweisen, je nachdem, ob der Vorgang eine exklusive Tabellensperre erhalten kann oder nicht.)
Also (zurück zur ursprünglichen Frage), TRUNCATE TABLE
ist eindeutig besser als DELETE FROM TABLE
wenn Sie die Tabelle leeren, aber die Struktur beibehalten möchten (Hinweis: TRUNCATE
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 der Erstellung von Protokollsicherungen beginnen oder Ihr Wiederherstellungsmodell auf einfach ändern. Sobald Sie eine dieser Aktionen ausgeführt haben, möchten Sie wahrscheinlich Ihre Protokolldatei als einmalige Operation verkleinern (NB: Protokolldatei - nur), um all diesen freien Speicherplatz zurückzugewinnen.
Zum Schluss noch etwas zu beachten - Tabellenstatistiken. Lauf UPDATE STATISTICS <TABLENAME>' after
KÜRZEN/
DELETE`, damit der Abfrageoptimierer nicht von alten Statistiken ausgelöst wird.
(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 beansprucht, und Tabellenscans, die auf dem 'leeren' Tabellenbereich ausgeführt werden. Ich denke, Sie müssen das Transaktionsprotokoll löschen und Ihre Datenbank verkleinern. Dieser StackOverflow-Artikel sollte Ihnen den Einstieg erleichtern.
Verwenden Sie TRUNCATE TABLE, wenn Sie dies in Zukunft tun möchten.
BEARBEITEN: Meine Aussage, dass TRUNCATE nicht protokolliert wird, war fehlerhaft. entfernt.