Zwingen, dass SQL Server die geschriebenen Abfragebedingungen ausführt?

13

Ich verwende SQL Server 2008 R2 und habe diese Pseudoabfrage (SP):

select ...
from ...
WHERE    @LinkMode IS NULL
     AND (myColumn IN (...very long-running query...))
     ...
     ...

Das Problem ist, dass die Ausführung der Abfrage sehr lange dauert - auch wenn ich den SP mit ausführe @LinkMode=2.

Wie Sie bemerkt haben, sollte die Langzeitabfrage nur ausgeführt werden, wenn @LinkMode null ist, was hier nicht der Fall ist. In meinem Fall @LinkMode = 2!

Wenn ich es jedoch ändere in:

 select ...
    from ...
    WHERE    1=2
         AND (myColumn IN (...very long time exeted query...))
     ...
     ...

der SP läuft schnell.

Ich habe zuvor gehört, dass der Optimierer manchmal die Reihenfolge der Kriterien optimieren kann .

Deshalb frage ich :

  • Auch wenn der Optimierer eine andere Route wählt, was kann schneller sein als zu überprüfen, ob =null? Ich meine, ich denke , dass Kontrolle if a==nullist viel schneller als die andere lange Abfrage läuft ...

  • Wie kann ich SQL Server zwingen , die Abfrage so auszuführen, wie ich sie geschrieben habe (in derselben Reihenfolge)?

Royi Namir
quelle

Antworten:

22

Sie tappen in die " Catch-All Query " -Falle, die hier von Gail Shaw sehr gut erklärt wird .

Um das Problem zusammenzufassen: SQL Server optimiert den erheblichen Aufwand für die Abfragekompilierung, indem ein Abfrageplan nach der Kompilierung zwischengespeichert und anschließend der Cache vor einer späteren Kompilierung auf einen übereinstimmenden Abfrageplan überprüft wird. Die "Übereinstimmung", die hier auftritt, ist rein textuell, so dass der tatsächliche Wert einer Variablen dies nicht beeinflusst.

Das ist in 99% der Fälle gut , aber in einigen Fällen auch schlecht . Ein Fall, in dem es schlecht ist, ist, wenn jemand versucht, eine WHERE-Klausel so zu konstruieren, als wäre sie eine kurzschließende IF-Anweisung in C usw. Dies funktioniert nicht gut, da der SQL-Compiler einen Abfrageplan erstellen muss, der unabhängig davon funktioniert Die einzige Möglichkeit, mit diesen "cleveren" logischen Umschaltbedingungen in der WHERE-Klausel umzugehen, besteht darin, einen einfachen Brute-Force-Plan zu erstellen, der nur die gesamte Tabelle durchsucht und die Zeilen nacheinander filtert , ohne irgendwelche Indizes zu nutzen.

Es überrascht nicht, dass sie dadurch gleichmäßig langsam werden, unabhängig von den Parametern / Variablenwerten.

RBarryYoung
quelle
8

Es gibt keine garantierte Möglichkeit, SQL Server zu zwingen, Ihre Klauselbedingungen in einer bestimmten Reihenfolge auszuführen. Der Optimierer wertet sie immer in der Reihenfolge aus, die er für richtig hält.

Was Sie tun können, ist etwa so:

IF @LinkMode IS NULL
BEGIN
    select ...
    from ...
    WHERE (myColumn IN (...very long time exeted query...))
         ...
         ...
END
ELSE
BEGIN
    select ...
    from ...
    WHERE ...
         ...
END
Esoterischer Bildschirmname
quelle
3

Wenn dies eine Option ist, verwenden Sie eine IF-Anweisung, um die entsprechende Form der Abfrage auszuführen. Außerdem teilen Sie in SQL der Datenbank-Engine mit, was zu tun ist, und nicht, wie es zu tun ist - die Dinge werden nicht von Anfang bis Ende ausgeführt. Es kann schwierig sein, genau vorherzusagen, was es tun wird. Das weißt du aber wahrscheinlich;)

Sam
quelle
2

Dynamisches SQL würde wahrscheinlich auch funktionieren, da in diesem Fall das Abfrageoptimierungsprogramm die tatsächlichen Werte zur Laufzeit abrufen sollte (korrigieren Sie mich, wenn ich falsch liege, ich bin mir nicht sicher, scheine mich aber zu erinnern, es für ähnliche Situationen zu verwenden) . Aber ich bin mit den anderen dabei, denn eine IF / ELSE-Klausel ist die einfachste und einfachste Lösung, die genau das tut, was benötigt wird.

Zum späteren Nachschlagen, falls Sie es noch nicht verwendet haben, finden Sie hier eine schrecklich hässliche Site mit einem funktionierenden Beispiel für dynamisches SQL: http://sqlusa.com/bestpractices/dynamicsql/

Kahn
quelle
1

Ich würde das IF / ELSE-Konstrukt empfehlen. Wenn aus irgendeinem Grund das bei Ihnen nicht funktioniert, können Sie immer die WITH RECOMPILE-Option in Betracht ziehen.

timvw
quelle
Könnten Sie vielleicht erläutern, wie das "if / else-Konstrukt" aussehen könnte? : D
jcolebrand
Ich wollte vorschlagen, OPTION (WITH RECOMPILE) zu verwenden, da dies jedes Mal einen idealen Plan generieren würde - die Kompilierungsverzögerung würde den Aufwand erhöhen, aber ich vermute, dass es in diesem Fall insgesamt besser ist.
SqlRyan