it-swarm-eu.dev

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

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?!?

27
TheDramaLlama

Sie haben bereits erfahren, warum TRUNCATE so viel schneller/besser/sexier ist als DELETE, aber es bleibt noch eine Frage zu beantworten:

Warum ist 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 .

42
Remus Rusanu

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
13
Akhil

(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:

  • Protokollspeicherplatznutzung: TRUNCATE protokolliert nur freigegebene Seiten/Bereiche *, während DELETE einzelne Zeilen protokolliert.
  • Sperrenverwendung: 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>' afterKÜRZEN/DELETE`, damit der Abfrageoptimierer nicht von alten Statistiken ausgelöst wird.

3
Simon Righarts

(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.

2
DaveE