2010-08-10 9 views
5

Ich habe eine SQL Server 2005-Datenbank, und ich habe versucht, Indizes auf die entsprechenden Felder setzen, um die DELETE Datensätze aus einer Tabelle mit Millionen von Zeilen zu beschleunigen (big_table hat nur 3 Spalten) , aber jetzt ist die DELETE Ausführungszeit sogar länger! (1 Stunde gegenüber 13 Minuten zum Beispiel)SQL Server DELETE ist langsamer mit Indizes

Ich habe eine Beziehung zwischen Tabellen, und die Spalte, die ich filtere meine DELETE von ist in der anderen Tabelle. Zum Beispiel

DELETE FROM big_table 
WHERE big_table.id_product IN (
SELECT small_table.id_product FROM small_table 
WHERE small_table.id_category = 1) 

Btw, ich habe auch versucht:

DELETE FROM big_table 
WHERE EXISTS 
(SELECT 1 FROM small_table 
WHERE small_table.id_product = big_table.id_product 
AND small_table.id_category = 1) 

und während es etwas schneller als die erste zu laufen scheint, ist es noch viel langsamer mit den Indizes als ohne.

I erstellten Indizes auf diesen Feldern:

  1. big_table.id_product
  2. small_table.id_product
  3. small_table.id_category

Meine LDF-Datei während der DELETE viel wächst.

Warum sind meine DELETE Abfragen langsamer, wenn ich Indizes auf meinen Tabellen habe? Ich dachte, sie sollten schneller laufen.

UPDATE

Okay, Konsens scheint Indizes wird eine riesige DELETE verlangsamen becuase der Index aktualisiert werden muss. Obwohl, ich verstehe immer noch nicht, warum es nicht alle DELETE alle Zeilen auf einmal, und aktualisieren Sie den Index nur einmal am Ende.

Ich war unter dem Eindruck von einigen meiner Lesung, dass Indizes DELETE beschleunigen würde, indem die Suche nach Feldern in der WHERE Klausel schneller.

Odetocode.com says:

„Indizes arbeitet auch nur, wenn für einen Datensatz in DELETE und UPDATE-Befehlen suchen, wie sie für SELECT-Anweisungen zu tun.“

Aber später in dem Artikel heißt es, dass zu viele Indizes die Leistung beeinträchtigen können.

Antworten auf Bob Fragen:

  1. 55 Millionen Zeilen in Tabelle
  2. 42 Millionen Zeilen würde System nicht ausgeführt
  3. ähnliche SELECT Anweisung gelöscht werden (Ausnahme vom Typ‘.OutOfMemoryException‘geworfen wurde)

ich die folgenden zwei Abfragen versucht:

SELECT * FROM big_table 
WHERE big_table.id_product IN (
SELECT small_table.id_product FROM small_table 
WHERE small_table.id_category = 1) 

SELECT * FROM big_table 
INNER JOIN small_table 
ON small_table.id_product = big_table.id_product 
WHERE small_table.id_category = 1 

Beide gescheitert nach für 25 min laufen mit dieser Fehlermeldung von SQL Server 2005:

An error occurred while executing batch. Error message is: Exception of type 'System.OutOfMemoryException' was thrown. 

Der Datenbankserver ist eine ältere Dual-Core-Xeon-Maschine mit 7,5 GB RAM. Es ist meine Spielzeug-Test-Datenbank :) Es läuft also nichts anderes.

Muss ich etwas spezielles mit meinen Indizes tun, nachdem ich sie CREATE richtig arbeiten lasse?

+3

Wie viele Zeilen sind in der Tabelle zu vermeiden? Wie viele Zeilen werden gelöscht? Wie lange würde eine ähnliche SELECT-Anweisung dauern? Wenn Sie wissen, wie schnell die SELECT-Anweisung ausgeführt wird, erhalten Sie möglicherweise einen Einblick, wie sich die Indizes auf DELETE auswirken. – bobs

+0

55 Mil Zeilen, 42 gelöscht, nicht abgeschlossen, siehe oben für weitere Details – JohnB

+0

Es dauert länger, da beim Ausführen eines Löschvorgangs die Indizes, die sich auf Ihre Tabelle beziehen, ebenfalls aktualisiert werden müssen. – WOPR

Antwort

27

Indizes machen Suchvorgänge schneller - wie der Index auf der Rückseite eines Buches.

Operationen, die die Daten (wie DELETE) ändern, sind langsamer, da sie die Indizes manipulieren. Betrachten Sie den gleichen Index auf der Rückseite des Buches. Sie haben mehr zu tun, wenn Sie Seiten hinzufügen, entfernen oder ändern, da Sie auch den Index aktualisieren müssen.

0

Sie können auch TSQL Erweiterung versuchen Syntax zu löschen und prüfen, ob er die Leistung verbessert:

DELETE FROM big_table 
FROM big_table AS b 
INNER JOIN small_table AS s ON (s.id_product = b.id_product) 
WHERE s.id_category =1 
+0

Das hat überhaupt nicht geholfen; Es dauerte exakt die selbe Zeit wie 'delete from big_table wo existiert (wähle 1 aus small_table wobei small_table.id_product = big_table.id_product und small_table.id_category = 1)' – JohnB

1

ich mit Bob Kommentar über Agree - wenn Sie große Datenmengen aus großen Tabellen löschen, die Indizes zu löschen können nehmen eine Weile, zusätzlich zu den Daten löschen die Kosten für die Geschäftsabwicklung. Wenn Sie alle Daten löschen, verursachen Sie Ereignisse, die neu indiziert werden.

In Bezug auf das Logfile-Wachstum; Wenn Sie nichts mit Ihren Logfiles tun, können Sie auf Simple Protokollierung wechseln; Ich bitte Sie jedoch dringend, sich über die Auswirkungen auf Ihre IT-Abteilung zu informieren, bevor Sie Änderungen vornehmen.

Wenn Sie das Löschen in Echtzeit durchführen müssen; Es ist oft eine gute Sache, die Daten entweder direkt in der Tabelle oder in einer anderen Tabelle als inaktiv zu markieren und diese Daten von Abfragen auszuschließen. dann komm später zurück und lösche die Daten, wenn die User nicht auf eine Sanduhr starren. Es gibt einen zweiten Grund, dies zu bedecken; Wenn Sie viele Daten aus der Tabelle löschen (was ich aufgrund Ihres Logfile-Problems vermute), dann werden Sie wahrscheinlich einen Indexdefrag ausführen, um den Index neu zu erstellen. Wenn Sie die Nutzer am Telefon nicht mögen, ist dies der richtige Weg.

0

JohnB löscht etwa 75% der Daten. Ich denke, das Folgende wäre eine mögliche und wahrscheinlich eine der schnellsten Lösungen gewesen. Erstellen Sie eine neue Tabelle und fügen Sie die Daten ein, die Sie behalten müssen, anstatt die Daten zu löschen. Erstellen Sie nach dem Einfügen der Daten die Indizes für diese neue Tabelle. Lassen Sie nun die alte Tabelle fallen und benennen Sie die neue Tabelle auf den gleichen Namen wie die alte um.

Das obige nimmt natürlich an, dass genügend Speicherplatz verfügbar ist, um die duplizierten Daten vorübergehend zu speichern.

0

Versuchen Sie so etwas Masse löschen (und damit vermeiden Wachstum Protokolldatei)

declare @continue bit = 1 

-- delete all ids not between starting and ending ids 
while @continue = 1 
begin 

    set @continue = 0 

    delete top (10000) u 
    from <tablename> u WITH (READPAST) 
    where <condition> 

    if @@ROWCOUNT > 0 
     set @continue = 1 

end 
Verwandte Themen