Ich habe Aussagen wie diese, die abgelaufen sind:
DELETE FROM [table] WHERE [COL] IN ( '1', '2', '6', '12', '24', '7', '3', '5')
Ich habe versucht, einen nach dem anderen zu machen:
DELETE FROM [table] WHERE [COL] IN ( '1' )
und bis jetzt ist es bei 22 Minuten und geht noch.
Die Tabelle enthält 260.000 Zeilen und vier Spalten.
Hat jemand eine Idee, warum dies so langsam ist und wie man es beschleunigt? Ich habe einen nicht eindeutigen, nicht gruppierten Index für die [COL], auf der ich das WHERE mache. Ich verwende SQL Server 2008 R2
Update: Ich habe keine Trigger auf dem Tisch.
where [col] = '1'
?Antworten:
Dinge, die dazu führen können, dass ein Löschvorgang langsam ist:
Sie können also herausfinden, was blockiert, und das Problem beheben oder die Löschvorgänge außerhalb der Geschäftszeiten ausführen, wenn sie die normale Produktionslast nicht beeinträchtigen. Sie können das Löschen stapelweise ausführen (nützlich, wenn Sie Trigger, Kaskadenlöschvorgänge oder eine große Anzahl von Datensätzen haben). Sie können die Indizes löschen und neu erstellen (am besten, wenn Sie dies auch außerhalb der Geschäftszeiten tun können).
quelle
select *
war schnell, aber das Löschen war wahnsinnig langsam. Dann wurde mir klar, dass es einen Fremdschlüssel für die Tabelle von einem anderen mit 2 Milliarden (!) Zeilen gab. Natürlich wurde die FK-Spalte nicht indiziert. Lösung: FK gelöscht, Zeilen gelöscht, FK neu erstellt. Die Neuerstellung des FK dauerte noch einige Zeit, war aber viel schneller.Deaktivieren Sie CONSTRAINT
ALTER TABLE [TableName] NOCHECK CONSTRAINT ALL;
Index deaktivieren
ALTER INDEX ALL ON [TableName] DISABLE;
Index neu erstellen
ALTER INDEX ALL ON [TableName] REBUILD;
CONSTRAINT aktivieren
ALTER TABLE [TableName] CHECK CONSTRAINT ALL;
Erneut löschen
quelle
alter index all on mytable disable
meisten Abfragen nicht mehr funktionieren. "Der Abfrageprozessor kann keinen Plan erstellen". Sie scheinen wieder zu funktionieren, sobald die Indizes neu erstellt und die Einschränkungen wieder aktiviert wurden.select referrer, fk from foreign_keys where is_disabled = 1
die Warnmeldungen überprüfen, die beim Deaktivieren der Indizes angezeigt wurden. Dann für jede betroffene untergeordnete Tabelle ,alter table mychild with check check constraint all
. Dies könnte einige untergeordnete Zeilen finden, die jetzt gelöscht werden müssen!select referrer, fk from foreign_keys where is_not_trusted = 1
diese ebenfalls.Das Löschen vieler Zeilen kann sehr langsam sein. Versuchen Sie, jeweils einige zu löschen, z.
delete top (10) YourTable where col in ('1','2','3','4') while @@rowcount > 0 begin delete top (10) YourTable where col in ('1','2','3','4') end
quelle
Präventivmaßnahmen
Suchen Sie mit Hilfe von
SQL Profiler
nach der Grundursache für dieses Problem. Möglicherweise wirdTriggers
die Ausführung verzögert. Es kann alles sein. Vergessen Sie nicht, dasDatabase Name
undObject Name
während desTrace
Starts auszuwählen, um das Scannen unnötiger Abfragen auszuschließen ...Filtern von Datenbanknamen
Filterung von Tabellen / gespeicherten Prozeduren / Triggernamen
Korrekturmaßnahme
Wie Sie sagten, enthält Ihre Tabelle 260.000 Datensätze ... und
IN Predicate
sechs Werte. Jetzt wird jeder Datensatz 260.000 Mal nach jedem Wert in durchsuchtIN Predicate
. Stattdessen sollte es die innere Verbindung wie unten sein ...Delete K From YourTable1 K Inner Join YourTable2 T on T.id = K.id
Fügen Sie die
IN Predicate
Werte in einTemporary Table
oder einLocal Variable
quelle
Wenn die Tabelle, aus der Sie löschen, BEFORE / AFTER DELETE-Trigger hat, kann etwas darin Ihre Verzögerung verursachen.
Wenn Sie Fremdschlüssel haben, die auf diese Tabelle verweisen, können zusätzliche UPDATEs oder DELETEs auftreten.
quelle
In meinem Fall war die Datenbankstatistik beschädigt. Die Aussage
delete from tablename where col1 = 'v1'
dauerte 30 Sekunden, obwohl es aber keine passenden Datensätze gab
delete from tablename where col1 = 'rubbish'
lief sofort
Laufen
update statistics tablename
Das Problem wurde behoben
quelle
Es ist möglich, dass andere Tabellen eine FK-Einschränkung für Ihre [Tabelle] haben. Daher muss die Datenbank diese Tabellen überprüfen, um die referenzielle Integrität aufrechtzuerhalten. Selbst wenn Sie alle benötigten Indizes haben, die diesen FKs entsprechen, überprüfen Sie deren Höhe.
Ich hatte die Situation, dass NHibernate fälschlicherweise doppelte FKs in denselben Spalten erstellt hat, jedoch mit unterschiedlichen Namen (was von SQL Server zugelassen wird). Die Ausführung der DELETE-Anweisung wurde drastisch verlangsamt.
quelle
Ist [COL] wirklich ein Zeichenfeld, das Zahlen enthält, oder können Sie die einfachen Anführungszeichen um die Werte entfernen? @Alex hat Recht, dass IN langsamer als = ist. Wenn Sie dies tun können, sind Sie besser dran:
DELETE FROM [table] WHERE [COL] = '1'
Aber noch besser ist es, Zahlen anstelle von Zeichenfolgen zu verwenden, um die Zeilen zu finden (SQL mag Zahlen):
DELETE FROM [table] WHERE [COL] = 1
Vielleicht versuchen Sie:
DELETE FROM [table] WHERE CAST([COL] AS INT) = 1
Stellen Sie in beiden Fällen sicher, dass Sie einen Index für die Spalte [COL] haben, um den Tabellenscan zu beschleunigen.
quelle
Überprüfen Sie den Ausführungsplan dieser Löschanweisung. Überprüfen Sie, ob die Indexsuche verwendet wird. Auch was ist der Datentyp von col?
Wenn Sie einen falschen Datentyp verwenden, ändern Sie die Aktualisierungsanweisung (z. B. von '1' auf 1 oder N'1 ').
Wenn ein Index-Scan verwendet wird, sollten Sie einen Abfragehinweis verwenden .
quelle
Ich habe diesen Artikel gelesen, er war wirklich hilfreich bei der Behebung von Unannehmlichkeiten
https://support.microsoft.com/en-us/kb/224453
Dies ist ein Fall von Waitresource KEY: 16: 72057595075231744 (ab74b4daaf17)
-- First SQL Provider to find the SPID (Session ID) -- Second Identify problem, check Status, Open_tran, Lastwaittype, waittype, and waittime -- iMPORTANT Waitresource select * from sys.sysprocesses where spid = 57 select * from sys.databases where database_id=16 -- with Waitresource check this to obtain object id select * from sys.partitions where hobt_id=72057595075231744 select * from sys.objects where object_id=2105058535
quelle
Wenn Sie alle Datensätze in der Tabelle löschen und nicht nur einige wenige, ist es möglicherweise viel schneller, die Tabelle einfach zu löschen und neu zu erstellen.
quelle
Nachdem ich ein SSIS-Paket überprüft hatte (da ein SQL Server Befehle sehr langsam ausführte), das in einem unserer Clients etwa 5 bis 4 Jahre vor dem Zeitpunkt eingerichtet wurde, als ich dies schrieb, stellte ich fest, dass die folgenden Aufgaben vorhanden waren: 1 ) Daten aus einer XML-Datei in eine Tabelle namens [Importbarcdes] einfügen.
2) Zusammenführungsbefehl für eine andere Zieltabelle unter Verwendung der oben genannten Tabelle als Quelle.
3) "Aus [Importbarcodes] löschen", um die Tabelle der Zeile zu löschen, die eingefügt wurde, nachdem die XML-Datei von der Aufgabe des SSIS-Pakets gelesen wurde.
Nach einer kurzen Überprüfung dauerte die Ausführung aller Anweisungen (SELECT, UPDATE, DELETE usw.) in der Tabelle ImportBarcodes, die nur eine Zeile enthielten, ca. 2 Minuten.
Erweiterte Ereignisse zeigten eine ganze Menge PAGEIOLATCH_EX-Wartebenachrichtigungen.
In der Tabelle waren keine Indizes vorhanden und es wurden keine Trigger registriert.
Bei genauer Betrachtung der Eigenschaften der Tabelle auf der Registerkarte "Speicher" und im Abschnitt "Allgemein" wurden im Feld "Datenbereich" mehr als 6 GIGABYTES Speicherplatz angezeigt, der auf Seiten zugewiesen wurde.
Was ist passiert:
Die Abfrage wurde in den letzten 4 Jahren jeden Tag über einen guten Teil der Zeit ausgeführt, wobei Daten in die Tabelle eingefügt und gelöscht wurden, wobei nicht verwendete Auslagerungsdateien zurückblieben, ohne sie freizugeben.
Dies war der Hauptgrund für die Warteereignisse, die von der erweiterten Ereignissitzung erfasst wurden, und für die langsam ausgeführten Befehle auf dem Tisch.
Durch Ausführen wurde
ALTER TABLE ImportBarcodes REBUILD
das Problem behoben, durch das der gesamte nicht verwendete Speicherplatz freigegeben wurde.TRUNCATE TABLE ImportBarcodes
hat etwas Ähnliches getan, mit dem einzigen Unterschied, dass alle Auslagerungsdateien und Daten gelöscht wurden.quelle
Älteres Thema, aber immer noch relevant. Ein weiteres Problem tritt auf, wenn ein Index so fragmentiert wurde, dass er eher ein Problem als eine Hilfe darstellt. In einem solchen Fall besteht die Antwort darin, den Index neu zu erstellen oder zu löschen und neu zu erstellen und die Löschanweisung erneut auszugeben.
quelle
Als Erweiterung von Andomars Antwort hatte ich oben ein Szenario, in dem die ersten 700.000.000 Datensätze (von ~ 1,2 Milliarden) sehr schnell verarbeitet wurden, wobei Blöcke von 25.000 Datensätzen pro Sekunde (ungefähr) verarbeitet wurden. Aber dann dauert es 15 Minuten, um eine Charge von 25.000 zu machen. Ich habe die Blockgröße auf 5.000 Datensätze reduziert und sie wurde auf die vorherige Geschwindigkeit zurückgesetzt. Ich bin nicht sicher, welchen internen Schwellenwert ich erreicht habe, aber das Problem bestand darin, die Anzahl der Datensätze weiter zu reduzieren, um die Geschwindigkeit wiederzuerlangen.
quelle
Öffnen Sie CMD und führen Sie diese Befehle aus
NET STOP MSSQLSERVER NET START MSSQLSERVER
Dadurch wird die SQL Server-Instanz neu gestartet. Versuchen Sie erneut, nach Ihrem Löschbefehl auszuführen
Ich habe diesen Befehl in einem Batch-Skript und führe ihn von Zeit zu Zeit aus, wenn ich auf solche Probleme stoße. Ein normaler PC-Neustart ist nicht derselbe. Daher ist ein Neustart der Instanz der effektivste Weg, wenn Probleme mit Ihrem SQL Server auftreten.
quelle