Ich verwende eine T-SQL- COALESCE
Funktion, bei der das erste Argument in etwa 95% der Fälle , in denen es ausgeführt wird, nicht null ist. Wenn das erste Argument ist NULL
, ist das zweite Argument ein ziemlich langwieriger Prozess:
SELECT COALESCE(c.FirstName
,(SELECT TOP 1 b.FirstName
FROM TableA a
JOIN TableB b ON .....)
)
Wenn zum Beispiel c.FirstName = 'John'
würde SQL Server noch die Unterabfrage ausführen?
Ich weiß mit der VB.NET- IIF()
Funktion, wenn das zweite Argument True ist, liest der Code immer noch das dritte Argument (obwohl es nicht verwendet wird).
quelle
CASE
immer von links nach rechts und immer Kurzschlüsse ausgewertet werden ).SELECT COALESCE((SELECT CASE WHEN RAND() <= 0.5 THEN 1 END), 1);
- mehrmals wiederholen. Sie werdenNULL
manchmal bekommen . Versuchen Sie es erneut mitISNULL
- Sie werden nieNULL
...Wie wäre es damit - wie mir Itzik Ben-Gan berichtet hat, dem Jaime Lafargue davon erzählt hat ?
Ergebnis:
Natürlich gibt es triviale Problemumgehungen, aber der Punkt ist immer noch, dass
CASE
nicht immer eine Auswertung von links nach rechts / ein Kurzschluss gewährleistet ist. Ich habe den Fehler hier gemeldet und er wurde als "beabsichtigt" geschlossen. Paul White hat dieses Connect-Objekt anschließend abgelegt und es wurde als "Fest" geschlossen. Nicht, weil es per se behoben wurde, sondern weil die Onlinedokumentation mit einer genaueren Beschreibung des Szenarios aktualisiert wurde, in dem Aggregate die Auswertungsreihenfolge einesCASE
Ausdrucks ändern können . Ich habe kürzlich mehr darüber hier gebloggt .BEARBEITEN Sie nur einen Nachtrag, obwohl ich einverstanden bin, dass dies Randfälle sind, dass Sie sich die meiste Zeit auf die Auswertung von links nach rechts und das Kurzschließen verlassen können und dass dies Fehler sind, die der Dokumentation widersprechen und wahrscheinlich irgendwann behoben werden ( das ist nicht eindeutig - siehe das folgende Gespräch in Bart Duncans Blog-Post, um zu sehen, warum), ich muss nicht zustimmen, wenn Leute sagen, dass etwas immer wahr ist, auch wenn es einen Einzelfall gibt, der es widerlegt. Wenn Itzik und andere einsame Bugs wie dieses finden, ist es zumindest möglich, dass es auch andere Bugs gibt. Und da wir den Rest der OP-Anfrage nicht kennen, können wir nicht mit Sicherheit sagen, dass er sich auf diesen Kurzschluss verlassen wird, aber am Ende von ihm gebissen wird. Für mich ist die sicherere Antwort:
Während Sie sich normalerweise darauf verlassen können
CASE
, wie in der Dokumentation beschrieben, von links nach rechts und den Kurzschluss zu bewerten, ist es nicht genau zu sagen, dass Sie dies immer tun können. Auf dieser Seite werden zwei Fälle gezeigt, in denen dies nicht zutrifft und keiner der Fehler in einer öffentlich verfügbaren Version von SQL Server behoben wurde.BEARBEITEN ist ein weiterer Fall (ich muss damit aufhören), in dem ein
CASE
Ausdruck nicht in der erwarteten Reihenfolge ausgewertet wird, obwohl keine Aggregate beteiligt sind.quelle
CASE
, das stillschweigend behoben wurdeMeine Meinung dazu ist , dass die Dokumentation macht es ziemlich klar , dass die Absicht ist , dass CASE Kurzschluss sollte. Wie Aaron erwähnt, gab es mehrere Fälle (ha!), In denen gezeigt wurde, dass dies nicht immer der Fall ist.
Bisher wurden alle diese Probleme als Fehler erkannt und behoben - obwohl dies nicht unbedingt in einer SQL Server-Version der Fall sein muss, die Sie heute kaufen und patchen können (der ständig klappende Fehler hat es noch nicht zu einem kumulativen Update-AFAIK geschafft). Der neueste potenzielle Fehler, der ursprünglich von Itzik Ben-Gan gemeldet wurde, muss noch untersucht werden (entweder Aaron oder ich werden ihn in Kürze zu Connect hinzufügen).
Bezogen auf die ursprüngliche Frage gibt es andere Probleme mit CASE (und damit COALESCE), bei denen nebenwirkende Funktionen oder Unterabfragen verwendet werden. Erwägen:
Das COALESCE-Formular gibt häufig NULL zurück. Weitere Informationen finden Sie unter https://connect.microsoft.com/SQLServer/feedback/details/546437/coalesce-subquery-1-may-return-null
Aufgrund der aufgezeigten Probleme mit Optimierungsumwandlungen und der Verfolgung gemeinsamer Ausdrücke kann nicht garantiert werden, dass CASE unter allen Umständen kurzschließt. Ich kann mir Fälle vorstellen, in denen es möglicherweise nicht einmal möglich ist, das Verhalten vorherzusagen, indem ich die Ergebnisse des öffentlichen Showplans inspiziere, obwohl ich heute keinen Repro dafür habe.
Zusammenfassend kann man sagen, dass man ziemlich sicher sein kann, dass CASE im Allgemeinen einen Kurzschluss verursacht (insbesondere dann, wenn eine vernünftige Person den Ausführungsplan überprüft und dieser Ausführungsplan mit einem Planleitfaden oder Hinweisen "durchgesetzt" wird), wenn dies jedoch erforderlich ist Als absolute Garantie müssen Sie SQL schreiben, das den Ausdruck überhaupt nicht enthält.
Ich glaube, das ist kein sehr zufriedenstellender Zustand.
quelle
Ich habe über einen anderen Fall kommen , wo
CASE
/COALESCE
nicht Kurzschluss zu tun. Die folgende TVF löst eine PK-Verletzung aus, wenn sie1
als Parameter übergeben wird.Wenn wie folgt aufgerufen
Oder als
Beide geben das Ergebnis
Dies zeigt, dass die
SELECT
(oder zumindest die Tabellenvariablenpopulation) immer noch ausgeführt wird und einen Fehler auslöst, obwohl dieser Zweig der Anweisung niemals erreicht werden sollte. Der Plan für dieCOALESCE
Version ist unten.Durch dieses Umschreiben der Abfrage wird das Problem anscheinend vermieden
Welches gibt Plan
quelle
Ein anderes Beispiel
Die Abfrage
Zeigt überhaupt keine Lesevorgänge
T2
an.Die Suche nach
T2
befindet sich unter einem Pass-Through-Prädikat und der Operator wird niemals ausgeführt. AberZeigt , dass
T2
gelesen wird. Auch wenn eigentlich nie ein Wert vonT2
benötigt wird.Das ist natürlich nicht wirklich überraschend, aber ich dachte, es lohnt sich, es dem Gegenbeispiel-Repository hinzuzufügen, schon allein deshalb, weil es die Frage aufwirft, was Kurzschluss in einer satzbasierten deklarativen Sprache überhaupt bedeutet.
quelle
Ich wollte nur eine Strategie erwähnen, die Sie vielleicht nicht in Betracht gezogen haben. Es mag hier kein Spiel sein, aber manchmal ist es nützlich. Überprüfen Sie, ob diese Änderung zu einer besseren Leistung führt:
Ein anderer Weg, dies zu tun, könnte folgender sein (im Grunde genommen äquivalent, aber Sie können bei Bedarf über die andere Abfrage auf mehr Spalten zugreifen):
Grundsätzlich ist dies eine Technik des "harten" Verbindens von Tabellen, aber einschließlich der Bedingung, wann überhaupt irgendwelche Zeilen verbunden werden sollten. Nach meiner Erfahrung hat dies zuweilen den Ausführungsplänen sehr geholfen.
quelle
Nein, das würde es nicht. Es würde nur laufen, wenn esc.FirstName
istNULL
.Sie sollten es jedoch selbst versuchen. Experiment. Sie sagten, Ihre Unterabfrage sei langwierig. Benchmark. Ziehen Sie daraus Ihre eigenen Schlüsse.Die @ Aaron-Antwort auf die ausgeführte Unterabfrage ist vollständiger.
Ich denke jedoch immer noch, dass Sie Ihre Abfrage überarbeiten und verwenden sollten
LEFT JOIN
. In den meisten Fällen können Unterabfragen entfernt werden, indem Sie Ihre Abfrage für die Verwendung vonLEFT JOIN
s überarbeiten .Das Problem bei der Verwendung von Unterabfragen besteht darin, dass Ihre Gesamtanweisung langsamer ausgeführt wird, da die Unterabfrage für jede Zeile in der Ergebnismenge der Hauptabfrage ausgeführt wird.
quelle
Der eigentliche Standard besagt, dass alle WHEN-Klauseln (sowie die ELSE-Klausel) analysiert werden müssen, um den Datentyp des Ausdrucks als Ganzes zu bestimmen. Ich müsste wirklich einige meiner alten Notizen herausholen, um festzustellen, wie ein Fehler behandelt wird. Aber 1/0 verwendet ganzzahlige Werte, also würde ich davon ausgehen, dass dies ein Fehler ist. Es ist ein Fehler mit dem Integer-Datentyp. Wenn Sie nur Nullen in der Zusammenführungsliste haben, ist es etwas schwieriger, den Datentyp zu bestimmen, und das ist ein weiteres Problem.
quelle