Sehr langsame Abfrage LÖSCHEN
Habe ich Probleme mit der SQL-Leistung. Für plötzliche Grund der folgenden Abfragen sehr langsam:
Ich habe zwei Listen enthält die Id einer bestimmten Tabelle. Wie lösche ich alle Datensätze aus der ersten Liste, wenn die Id bereits vorhanden ist in der zweiten Liste:
DECLARE @IdList1 TABLE(Id INT)
DECLARE @IdList2 TABLE(Id INT)
-- Approach 1
DELETE list1
FROM @IdList1 list1
INNER JOIN @IdList2 list2 ON list1.Id = list2.Id
-- Approach 2
DELETE FROM @IdList1
WHERE Id IN (SELECT Id FROM @IdList2)
Ist es möglich, die zwei Listen enthält mehr als 10.000 Datensätze. In diesem Fall werden beide Abfragen dauert jeweils mehr als 20 Sekunden ausgeführt werden.
Den Ausführungsplan zeigte auch etwas, was ich nicht verstehe. Vielleicht erklärt warum es so langsam ist:
Füllte ich die beiden Listen mit 10.000 sequenziell ganze zahlen, so dass beide Liste enthaltenen Wert 1-10.000 als Ausgangspunkt.
Wie Sie sehen können beide Abfragen zeigt für @IdList2 die Tatsächliche Anzahl von Zeilen ist 50.005.000!!. @IdList1 korrekt ist (die Tatsächliche Anzahl von Zeilen ist 10.000)
Ich weiß, es gibt andere Lösungen wie man dieses Problem lösen. Wie füllen Sie eine Dritte Liste nur das entfernen aus der ersten Liste. Aber meine Frage ist:
Warum sind diese delete-Anfragen so langsam und warum sehe ich diese seltsame Abfrage-Pläne?
- Ist das ein problem, dass vielleicht auftreten in einem realen Szenario, oder, gerade in dieser specilaized situation?
- Die zugrunde liegenden Probleme keine Statistiken kompiliert Sie für table-Variablen (und Mangel an nützlichen Indizes auf Ihnen) ist sehr Häufig.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Fügen Sie einen Primärschlüssel für Ihre Tabelle-Variablen und sehen, wie Sie Schreien
weil es keinen index für diese Tabelle Variablen, joins oder Unterabfragen müssen prüfen, die auf der Größenordnung von 10.000 x 10.000 = 100,000,000 Paare von Werten.
@IdList1
?SQL Server kompiliert den plan, wenn die table-variable leer ist und nicht neu kompilieren, wenn Zeilen Hinzugefügt werden. Versuchen
Dieser berücksichtigt die tatsächliche Anzahl der Zeilen in der Tabelle enthalten sind variable und loszuwerden, die nested loops-plan
Natürlich das erstellen eines index für
Id
über eine Einschränkung kann auch von Vorteil sein, für andere Abfragen über die Tabelle variable zu.DELETE
- Anweisung wird kompiliert, wenn die table-Variablen leer sind. Dann (aufgrundOPTION (RECOMPILE)
) es wird neu kompiliert am Punkt derDELETE
und können die Berücksichtigung der tatsächlichen Anzahl von Zeilen, nach der table-Variablen aufgefüllt werden.Tabellen in die table-Variablen können primary keys, also, wenn Sie Ihre Daten unterstützt die Einzigartigkeit dieser
Id
s, können Sie in der Lage sein, um die Leistung zu verbessern, indem Sie fürMögliche Lösungen:
1) Versuchen Sie, erstellen Sie Indizes so
1.1), Wenn Liste{1/2}.Die Spalte Id hat einzigartige Werte, dann definieren Sie einen eindeutigen gruppierten index mit einem PK-Einschränkung wie diese:
1.2) Wenn Die Liste{1/2}.Id-Spalte kann mit doppelten Werten, dann definieren Sie einen eindeutigen gruppierten index mit einem PK-Einschränkung mit einem dummy
IDENTITY
Spalte wie folgt:2) Versuchen Sie, fügen Sie
HASH JOIN
Abfrage Hinweis wie dieser:Sind Sie mit
Table Variables
entweder fügen Sie einen Primärschlüssel für die Tabelle oder ändern Sie Sie, umTemporary Tables
und fügen Sie eineINDEX
. Dies führt zu viel mehr Leistung. Als Faustregel gilt, wenn die Tabelle ist nur klein, verwendenTABLE Variables
jedoch, wenn die Tabelle erweitert, und viele Daten enthält, dann verwenden Sie entweder eine temp-Tabelle.Ich würde geneigt sein, zu versuchen,
Kein löschen erforderlich.
I need to delete all records from the first list if the Id's already exists in the second list
Versuchen, diese Alternative syntax:
BEARBEITEN.....................
Versuchen Sie es mit #temp-Tabellen mit Indizes statt.
Hier ist ein Allgemeines Beispiel, wo "DepartmentKey" ist die PK und FK.