Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

IsNULL und Coalesce ordnungsgemäße Verwendung

Dies wurde gehasht und erneut gehasht. Zusätzlich zu den Tipp, auf den ich im Kommentar hingewiesen habe und die Links und die Erklärung @xQbert, die oben gepostet wurden, hier ist auf Anfrage eine Erklärung von COALESCE vs. ISNULL mit einer Unterabfrage. Betrachten wir diese beiden Abfragen, die in Bezug auf die Ergebnisse identisch sind:

SELECT COALESCE((SELECT TOP (1) name FROM sys.objects), N'foo');

SELECT ISNULL((SELECT TOP (1) name FROM sys.objects), N'foo');

(Kommentare zur Verwendung von TOP ohne ORDER BY an /dev/null/ danke.)

Im COALESCE-Fall wird die Logik tatsächlich so erweitert:

SELECT CASE WHEN (SELECT TOP (1) ...) IS NULL
    THEN (SELECT TOP (1) ...)
    ELSE N'foo'
END

Bei ISNULL passiert das nicht. Es gibt eine interne Optimierung, die dafür zu sorgen scheint, dass die Unterabfrage nur einmal ausgewertet wird. Ich weiß nicht, ob jemand außerhalb von Microsoft genau weiß, wie diese Optimierung funktioniert, aber Sie können dies feststellen, wenn Sie die Pläne vergleichen. Hier ist der Plan für die COALESCE-Version:

Und hier ist der Plan für die ISNULL-Version - beachten Sie, wie viel einfacher es ist (und dass der Scan nur einmal stattfindet):

Im COALESCE-Fall erfolgt der Scan zweimal. Das heißt, die Unterabfrage wird zweimal ausgewertet, auch wenn sie keine Ergebnisse liefert. Wenn Sie eine WHERE-Klausel hinzufügen, sodass die Unterabfrage 0 Zeilen ergibt, sehen Sie eine ähnliche Ungleichheit – die Planformen können sich ändern, aber Sie sehen immer noch eine doppelte Suche und Suche oder einen Scan für den COALESCE-Fall. Hier ist ein etwas anderes Beispiel:

SELECT COALESCE((SELECT TOP (1) name FROM sys.objects 
    WHERE name = N'no way this exists'), N'foo');

SELECT ISNULL((SELECT TOP (1) name FROM sys.objects 
    WHERE name = N'no way this exists'), N'foo');

Der Plan für die COALESCE-Version dieses Mal - Sie können wieder den gesamten Zweig sehen, der die Unterabfrage wörtlich wiederholt:

Und wieder ein viel einfacherer Plan, der mit ISNULL ungefähr die Hälfte der Arbeit erledigt:

Sie können diese Frage auch auf dba.se für weitere Diskussionen sehen:

Mein Vorschlag ist dieser (und Sie können meine Gründe dafür im Tipp und in der obigen Frage sehen):Vertrauen, aber überprüfen. Ich verwende immer COALESCE (weil es ANSI-Standard ist, mehr als zwei Argumente unterstützt und nicht ganz so wackelige Dinge mit der Datentyppriorität macht), es sei denn Ich weiß, dass ich eine Unterabfrage als einen der Ausdrücke verwende (an die ich mich nicht erinnern kann, dass ich sie jemals außerhalb theoretischer Arbeiten wie dieser gemacht habe), oder ich habe ein echtes Leistungsproblem und möchte nur vergleichen, ob COALESCE vs. ISNULL welche hat erheblicher Leistungsunterschied (den ich außerhalb des Unterabfragefalls noch finden muss). Da ich COALESCE fast immer mit Argumenten ähnlicher Datentypen verwende, muss ich selten andere Tests durchführen, als auf das zurückzublicken, was ich in der Vergangenheit darüber gesagt habe (ich war auch der Autor von der aspfaq-Artikel, auf den xQbert hingewiesen hat , vor 7 Jahren).