MSSQL Large Delete


7

Ich habe eine Tabelle in einer MSSQL-Datenbank, die mehr als 100 Millionen Datensätze enthält, die über Daten im Wert von etwa 100 Tagen verteilt sind. Ich muss einige dieser Daten basierend auf dem Datum löschen, das ein indiziertes Feld in der Tabelle ist. Ich habe versucht, ein DELETE FROM für ein einzelnes Datum auszuführen, aber die Ausführung hat lange gedauert und die Serverleistung beeinträchtigt. Gibt es eine bessere Möglichkeit, eine so große Anzahl von Datensätzen zu löschen? Einige dieser Daten werden noch benötigt, daher kann ich das Abschneiden leider nicht verwenden.

Vielen Dank Nick

Antworten:


2

Ich hatte den besten Erfolg, wenn ich ähnliche Aufgaben mit folgendem Ablauf erledigte:

  1. Kopieren Sie die zu speichernden Daten in eine temporäre Tabelle
  2. Schneiden Sie die ursprüngliche Tabelle ab, um alle Daten zu löschen
  3. Verschieben Sie alles von der temporären Tabelle zurück in die ursprüngliche Tabelle

Ein wesentlicher Vorteil davon ist, dass Ihre Indizes neu erstellt werden, wenn Sie die Daten wieder in die ursprüngliche Tabelle einfügen.


3
Ich kann sehen, wie das funktionieren würde, aber es klingt ein bisschen zu riskant für meinen Geschmack. Ich persönlich würde mich nicht wohl fühlen, wenn ich dies zum Beispiel in einer OLTP-Produktionsdatenbank mit hohem Durchsatz mache, aber das bin nur ich.
John Sansom

Vergessen Sie nicht, Ihre Indizes und Einschränkungen neu zu erstellen, wenn Sie diese Methode verwenden
Nick Kavadias

3

Wenn Sie SQL Server-Partitionierung verwenden, beispielsweise basierend auf der Datumsspalte, hätten Sie möglicherweise die Partitionen ausgetauscht, die nicht mehr benötigt werden. Eine Überlegung für eine zukünftige Implementierung vielleicht.

Ich denke, Ihre einzige Möglichkeit besteht darin, die Daten in kleineren Stapeln anstatt in einem Treffer zu löschen, um mögliche Blockierungsprobleme zu vermeiden.


1
Klingt nach einem perfekten Anwendungsfall für die Partitionierung von Schiebefenstern. +1
Aaron Alton

1

Sie können alle Indizes in der Tabelle TROPFEN, AUS DER Tabelle LÖSCHEN und dann die Indizes erneut erstellen. Dies könnte die Dinge beschleunigen, hängt jedoch vom Prozentsatz der Datensätze ab, die nicht gelöscht werden.


0

Sie können kleinere Blöcke löschen. Anstatt zu sagen, eine Woche, die es wert ist, nur einen Tag lang zu versuchen. Wenn das zu viel ist, versuchen Sie es jeweils nur eine Stunde lang.


0

Eine andere Möglichkeit wäre, nur die gewünschten Daten in eine andere Tabelle auszuwählen. Auf diese Weise können Sie die Partitionierung am Datum einrichten.

Wenn der Datumsindex der Clustered-Index war, sollten die Löschvorgänge schneller erfolgen, da sie alle auf der Festplatte nahe beieinander liegen würden.


0

Ich mag oder befürworte den erwähnten Vorschlag für eine temporäre Tabelle nicht. Wenn der Server zwischen dem Löschschritt und dem Einfügeschritt ausfällt, gehen die Daten verloren.

Ich würde eher mit einer der folgenden Möglichkeiten arbeiten:

BCP die Daten, die Sie behalten möchten (BCP mit QUERYOUT), abschneiden, erneut importieren. Gleicher Effekt wie die temporäre Tabelle mit geringerem Gesamtrisiko.

Kopieren Sie die Daten in eine andere permanente Tabelle, entweder in derselben oder in einer anderen Datenbank, und ziehen Sie sie dann zurück.

In Stapeln mit der SET ROWCOUNT-Technik löschen. Wenn Sie vorsichtig und geschickt sind, können Sie diese Schleife so ausführen, dass sie außerhalb des Gültigkeitsbereichs der Schleife liegt, sodass die Löschvorgänge unabhängig voneinander festgeschrieben werden. Sofern Ihr Clustered-Index nicht mit dem Löschen von Daten zusammenhängt, führt dies zu einer umfassenden Tabellenfragmentierung.


0

Wahrscheinlich ist es in einigen hochvolumigen OLTP-Datenbanken besser, Daten überhaupt nicht zu löschen. Entwickler können das Feld "IsDeleted" oder ähnliches erstellen. Dies ist jedoch eine Überlegung für die Zukunft.

Als Antwort haben Sie akzeptiert. Ich glaube nicht, dass es schneller funktioniert als der einfache DELETE-Ansatz, wenn Sie 100 MB Daten kopieren. Es wird eine sehr hohe Last und ein großes Wachstum des Transaktionsprotokolls sein. Im Allgemeinen hängt es davon ab, wie viele dieser Daten Sie nach Abschluss des Löschvorgangs unberührt lassen möchten.

Was ich empfehlen würde ist

1) Wenn Sie Ihre Abfrage in nicht aktiven Stunden ausführen können, sollten Sie eine exklusive Tabellensperre ausstellen und dann Datensätze löschen. Dies spart Zeit, die SQL Server für die Weitergabe von Sperren an viele einzelne Zeilen benötigt

2) Wenn der erste Ansatz nicht möglich ist, dann löschen Sie ihn nach Brocken. Ich werde John Sansom zustimmen. Probleme beginnen, wenn es eine sehr große Transaktion gibt, die viele Transaktionen anderer aktiver Benutzer blockiert ... Sie müssen also in kleinen Teilen löschen, jede in ihrer eigenen Transaktion ...

3) Sie können auch vor / nach dem Löschen vorübergehend Trigger und Einschränkungen (einschließlich Fremdschlüssel) ausschalten (oder löschen und dann neu erstellen). Es besteht jedoch ein Integritätsrisiko, und dieser Ansatz erfordert einige Experimente.

AFAIK: Das Deaktivieren / Aktivieren von Indizes verbessert die Situation nicht, da beim Löschen von Datensätzen "Lücken" in den Indexbäumen auftreten. Dies kann sich also auf die Leistung der nächsten SQL-Abfragen für dieselbe Tabelle und früher oder später auf Sie auswirken Möglicherweise möchten Sie die Indizes neu erstellen, ich sehe jedoch keine Auswirkungen darauf, wie Indizes (auch wenn Sie möglicherweise auch Indizes haben) die Geschwindigkeit des Löschvorgangs verringern können

In den meisten Fällen ist die Leistung von DELETE schlecht, wenn Indizes nicht von der DELETE-Abfrage verwendet werden (Sie können den Abfrageplan überprüfen) oder wenn Sie zu viele Fremdschlüssel oder eine starke Triggerlogik haben.


0

In Stücken löschen.

Führen Sie eine Löschung basierend auf einer Auswahl gemäß Ihren Kriterien durch, aber die Auswahl hat TOP 100000 - so werden bei jedem Anruf nur 100000 Zeilen gelöscht. Rufen Sie an, bis nicht mehr gelöscht wird.

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.