Gibt es eine Möglichkeit, eine Variable in einer WHERE-Klausel nur einmal auf Null zu prüfen?

11

Ich habe eine Abfrage für eine große Tabelle, die so aussieht:

declare @myIdParam int = 1

select * 
from myTable
where (@myIdParam is null or myTable.Id = @myIdParam)

In der where-Klausel gibt es mehrere ähnliche Bedingungen wie diese, und es gibt auch viele Verknüpfungen, aber dies ist eine Zusammenfassung.

Wenn @myIdParam null ist, möchten wir die Ergebnisse mit diesem Parameter nicht einschränken.

Ich bin kein DB-Profi, aber aus meinen Tests geht hervor, dass diese NULL-Prüfung für jeden Datensatz durchgeführt und in keiner Weise optimiert wird.

Wenn ich die Nullprüfung entferne und davon ausgehe, dass der Parameter nicht null ist, wird die Abfrage sofort zurückgegeben. Andernfalls dauert es bis zu zehn Sekunden.

Gibt es eine Möglichkeit, dies zu optimieren, sodass die Überprüfung zur Laufzeit nur einmal durchgeführt wird?

Mystagoge
quelle
1
Schauen Sie sich diese Antwort an: stackoverflow.com/questions/3415582/… tl; dr useOPTION(RECOMPILE)
vercelli
@vercelli das macht den Trick. Wenn man bedenkt, dass es bei dieser Frage wirklich um optionale Parameter geht, würde ich sagen, dass es sich um ein Duplikat der von Ihnen verknüpften handelt.
Mystagoge
Wahrscheinlich, aber es ist ein Beitrag von vor 6 Jahren. Vielleicht gibt es mit SqlServer 2014 oder 2016 einen neuen Ansatz. (Ich habe es 2014 ohne Neukompilierung getestet und für immer
gebraucht
Da Ihre eigentliche Abfrage viele optionale Parameter enthält, bietet dynamisches SQL die beste Leistung. Unter sommarskog.se/dyn-search.html finden Sie einen ausführlichen Artikel zu diesem Thema.
Dan Guzman
@DanGuzman mit WITH RECOMPILE, wie in der verknüpften Frage vercelli beschrieben, verkürzte die Abfragezeit mit hochselektiven Kriterien von knapp einer Minute auf praktisch sofort. Ich halte dies für die beste Option, um Leistung und Lesbarkeit in Einklang zu bringen.
Mystagoge

Antworten:

8

Eine Möglichkeit besteht darin, dynamisches SQL zu verwenden und eine Nullprüfung zu verwenden, um optional diesen Teil der where-Klausel hinzuzufügen.

declare @myIdParam int = 1
declare @vc_dynamicsql varchar(max)

set @vc_dynamicsql = 'select * from myTable where 1=1'

if @myIdParam is not null
    set @vc_dynamicsql = @vc_dynamicsql + ' and  myTable.Id = @myIdParam'

EXECUTE sp_executesql @vc_dynamicsql
Mystagoge
quelle
2
Ich würde es wirklich vorziehen, dies nicht zu tun, aber es ist eine Lösung. Ich hoffe, dass jemand mit einem viel besseren kommt.
Mystagoge
1
Dies ist der beste Weg, um diese Klasse von Suchabfragen zu behandeln. Die Stackoverflow-Antwort, auf die @vercelli verweist, enthält hervorragende Referenzen dazu.
Max Vernon
Dies ist die beste Methode, aber ich habe festgestellt, dass der Parameter @params für sp_ExecuteSQLfehlt und der @vc_dynamicsqlParameter a sein muss NVARCHAR.
James Anderson
4

Jedes Mal, wenn Sie eine Funktion um eine Spalte "ISNULL (@var, table.col)" setzen, entfernen Sie beispielsweise die Fähigkeit von SQL, einen Index zu verwenden. Dies ist wirklich die leistungsstärkste Option, wenn Sie sie in einer einzelnen Abfrage behalten möchten.

@var IS NULL or @var = table.col

Ansonsten haben Sie zwei Möglichkeiten. Das erste ist dynamisches SQL und die Antwort von @ Mystagogue reicht dafür aus, andernfalls können Sie zwei Abfragen wie diese eingeben:

IF @var is NULL
     SELECT * FROM table
ELSE
     SELECT * FROM table WHERE @var = col

Sowohl in diesem Format als auch in dynamischem SQL erhalten Sie für jede Abfrage einen anderen Abfrageplan (was möglicherweise zu einer besseren Leistung führt).

Kenneth Fisher
quelle
Die SQL in der Frage verwendet weder ISNULL noch eine andere Funktion.
Mystagoge
@MystagogueI Ich habe auf eine jetzt gelöschte Antwort verwiesen.
Kenneth Fisher
0

Ja, du kannst:

declare @myIdParam int = 1;

select *
from myTable
where nullif(@myIdParam, myTable.Id) is null;

Beachten Sie jedoch, dass die nullif()Funktion im Wesentlichen ein Wrapper ist case. Es ist keine Silberkugel, ORdie die Abfrage auf magische Weise eliminiert und damit beschleunigt.

Roger Wolf
quelle
Die Verwendung von Funktionen in einer where-Klausel wirkt sich negativ auf die Leistung aus, da sie die Verwendung von Indizes verhindert (oder wie ich gehört habe)
Mystagogue
@Mystagogue, ja - normalerweise sind die Suchbedingungen nicht SARG-fähig. Leider ist dies die einzige Möglichkeit, Ihre Frage zu beantworten, ohne auf dynamisches SQL oder mehrere UNIONs zurückzugreifen. Als ich genau diese Aufgabe hatte, entschied ich mich für dynamisches SQL.
Roger Wolf