Irgendeine Idee, warum das IF EXISTS
so viel länger laufen und so viel mehr liest? Ich habe auch die Select-Anweisung geändert SELECT TOP 1 [dlc].[id]
und sie nach 2 Minuten getötet.
Wie ich in meiner Antwort auf diese verwandte Frage erklärte:
Wie (und warum) wirkt sich TOP auf einen Ausführungsplan aus?
Using EXISTS
führt ein Zeilenziel ein, bei dem das Optimierungsprogramm einen Ausführungsplan erstellt, mit dem die erste Zeile schnell lokalisiert werden soll. Dabei wird davon ausgegangen, dass die Daten gleichmäßig verteilt sind. Wenn Statistiken beispielsweise zeigen, dass 100 erwartete Übereinstimmungen in 100.000 Zeilen vorliegen, wird davon ausgegangen, dass nur 1.000 Zeilen gelesen werden müssen, um die erste Übereinstimmung zu finden.
Dies führt zu längeren Ausführungszeiten als erwartet, wenn sich diese Annahme als fehlerhaft herausstellt. Wenn SQL Server beispielsweise eine Zugriffsmethode (z. B. einen ungeordneten Scan) auswählt, bei der der erste übereinstimmende Wert sehr spät in der Suche gefunden wird, kann dies zu einem fast vollständigen Scan führen. Wenn andererseits eine übereinstimmende Zeile in den ersten Zeilen gefunden wird, ist die Leistung sehr gut. Dies ist das grundlegende Risiko bei Zeilenzielen - inkonsistente Leistung.
Als vorübergehende Korrektur habe ich es geändert, um eine Zählung (*) durchzuführen und diesen Wert einer Variablen zuzuweisen
Es ist normalerweise möglich, die Abfrage so umzuformulieren, dass kein Zeilenziel zugewiesen wird. Ohne das Zeilenziel kann die Abfrage immer noch beendet werden, wenn die erste übereinstimmende Zeile gefunden wird (wenn sie korrekt geschrieben wurde), aber die Strategie des Ausführungsplans ist wahrscheinlich anders (und hoffentlich effektiver). Offensichtlich erfordert count (*) das Lesen aller Zeilen, daher ist es keine perfekte Alternative.
Wenn Sie SQL Server 2008 R2 oder höher ausführen , können Sie im Allgemeinen auch das dokumentierte und unterstützte Ablaufverfolgungsflag 4138 verwenden , um einen Ausführungsplan ohne Zeilenziel abzurufen. Dieses Flag kann auch mithilfe des unterstützten Hinweises angegeben OPTION (QUERYTRACEON 4138)
werden. Beachten Sie jedoch , dass dafür die Berechtigung sysadmin zur Laufzeit erforderlich ist , sofern dies nicht zusammen mit einem Planungshandbuch verwendet wird.
Unglücklicherweise
Keines der oben genannten ist mit einer IF EXISTS
bedingten Anweisung funktionsfähig . Dies gilt nur für reguläre DML. Es wird mit der alternativen arbeiten SELECT TOP (1)
Sie versucht Formulierung. Das kann durchaus besser sein als die Verwendung COUNT(*)
, bei der, wie bereits erwähnt, alle qualifizierten Zeilen gezählt werden müssen.
Es gibt jedoch eine Reihe von Möglichkeiten, diese Anforderung auszudrücken, mit denen Sie das Zeilenziel vermeiden oder steuern können, während Sie die Suche vorzeitig beenden. Ein letztes Beispiel:
DECLARE @Exists bit;
SELECT @Exists =
CASE
WHEN EXISTS
(
SELECT [dlc].[ID]
FROM TableDLC [dlc]
JOIN TableD [d]
ON [d].[ID] = [dlc].[ID]
JOIN TableC [c]
ON [c].[ID] = [d].[ID2]
WHERE [c].[Name] <> [dlc].[Name]
)
THEN CONVERT(bit, 1)
ELSE CONVERT(bit, 0)
END
OPTION (QUERYTRACEON 4138);
IF @Exists = 1
BEGIN
...
END;
IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
.