Wird der Kurzschluss der SQL WHERE-Klausel ausgewertet?

142

Werden boolesche Ausdrücke in SQL WHERE-Klauseln kurzgeschlossen ?

Beispielsweise:

SELECT * 
FROM Table t 
WHERE @key IS NULL OR (@key IS NOT NULL AND @key = t.Key) 

Wenn @key IS NULL als wahr ausgewertet wird, wird @key NICHT NULL UND @key = t.Key ausgewertet?

Wenn nein, warum nicht?

Wenn ja, ist es garantiert? Ist es Teil von ANSI SQL oder datenbankspezifisch?

Wenn datenbankspezifisch, SqlServer? Orakel? MySQL?

Greg Dean
quelle
Ist die Klausel @key NICHT NULL redundant? Die @ key IS NULL-Klausel auf der LHS kümmert sich um dieses Nein?
Spender
10
@splender - hängt von der Antwort auf die Frage ab
Greg Dean
@ Greg: Ich stimme dem Spender zu. Ich sehe nicht, dass das Fehlen oder Vorhandensein von Kurzschlüssen einen Unterschied macht. Wenn @key IS NULL ist, gibt @key = t.Key immer false zurück, da NULL! = NULL (deshalb verwenden wir schließlich IS NULL).
Michael Madsen
14
@Michael und @spender - Der Punkt der Frage ist, ob die zweite Bedingung bewertet wird oder nicht. Der Punkt der Frage ist nicht, ob diese spezifische SQL-Anweisung in so wenigen Zeichen wie möglich geschrieben ist. In komplizierteren Beispielen wäre es zweifellos wichtig, als ob die where-Klausel kurzschließt, Sie könnten Ausdrücke schreiben, die sonst fehlerhaft wären.
Greg Dean
2
Kurzschluss bedeutet, die Bedingungen von links nach rechts zu bewerten. Unter einer Bedingung, wie WHERE a = 1 AND b = 2es für das Datenbankmodul effizient sein könnte, zuerst alle Zeilen mit b = 2 zu finden und dann mit a = 1 zu filtern. Wenn Sie um Garantie bitten, wird das Optimierungsprogramm unbrauchbar.
Salman A

Antworten:

72

ANSI SQL Draft 2003 5WD-01-Framework-2003-09.pdf

6.3.3.3 Reihenfolge der Regelbewertung

[...]

Wenn die Priorität nicht durch die Formate oder durch Klammern bestimmt wird, wird eine effektive Bewertung der Ausdrücke im Allgemeinen von links nach rechts durchgeführt. Es ist jedoch implementierungsabhängig, ob Ausdrücke tatsächlich von links nach rechts ausgewertet werden, insbesondere wenn Operanden oder Operatoren dazu führen können, dass Bedingungen ausgelöst werden, oder ob die Ergebnisse der Ausdrücke ermittelt werden können, ohne alle Teile des Ausdrucks vollständig auszuwerten.

Gemeinschaft
quelle
4
Implementierungsabhängig? Toll. Gut zu wissen auch. Zumindest CASEist kurzgeschlossen.
Dakab
3
Bedeutet das nicht, dass die Ausdrucksbewertungen schlecht definiert sind? "(0 = 0 ODER NULL)" ist immer NULL, wenn alle Begriffe ausgewertet werden, aber immer wahr, wenn von links nach rechts ausgewertet und kurzgeschlossen wird.
Benutzer48956
6
SQL ist eine deklarative Sprache, die im Grunde die Logik der Berechnung ausdrückt, ohne ihren Kontrollfluss zu beschreiben. welche Art widerspricht dem imperativen Stil der Kurzschlussbewertung und ihren Konsequenzen.
Jorge Garcia
Ich hatte nicht so darüber nachgedacht @JorgeGarcia. Ich denke, die Kurzschlussauswertung erzwingt implizit einen Befehl für Operationen. Ich ringe mit einem Code, bei dem dies möglicherweise die Wurzel eines subtilen Problems ist. Danke für den Einblick.
Carnot Antonio Romero
58

Aus dem oben Gesagten ist ein Kurzschluss nicht wirklich verfügbar.

Wenn Sie es brauchen, schlage ich eine Case-Erklärung vor:

Where Case when Expr1 then Expr2 else Expr3 end = desiredResult

Expr1wird immer ausgewertet, aber nur einer von Expr2und Expr3wird pro Zeile ausgewertet.

PMc
quelle
3
Das hängt von der Implementierung des RDBMS ab, die ich annehme. Zumindest für SQL Server gibt es mindestens eine Ausnahme, die dokumentiert ist, um dieses Verhalten nicht anzuzeigen (dh Kurzschluss). Siehe CASE (Transact-SQL) - Anmerkungen . Ich habe diesen Fall in dieser Antwort zitiert , die ich auf die Frage SQL - Explizite Reihenfolge der WHERE-Bedingungen gegeben habe. .
TT.
1
Fall Ausdruck , nicht Aussage.
Jarlh
19

Ich denke, dies ist einer der Fälle, in denen ich es aus drei Gründen so schreiben würde, als würde es nicht kurzschließen.

  1. Denn für MSSQL wird es nicht gelöst, indem man BOL an der offensichtlichen Stelle betrachtet. Für mich ist es daher kanonisch mehrdeutig.

  2. weil ich zumindest dann weiß, dass mein Code funktionieren wird. Und was noch wichtiger ist, auch diejenigen, die nach mir kommen, damit ich sie nicht dazu bringe, sich immer wieder die gleiche Frage zu stellen.

  3. Ich schreibe oft genug für mehrere DBMS-Produkte und möchte mich nicht an die Unterschiede erinnern müssen, wenn ich sie leicht umgehen kann.

dkretz
quelle
4
Toller Vorschlag. Es beantwortet die Frage nicht, aber es ist eine großartige pragmatische Sichtweise. also +1
Greg Dean
12

Ich glaube nicht, dass ein Kurzschluss in SQL Server (2005) garantiert ist. SQL Server führt Ihre Abfrage über seinen Optimierungsalgorithmus aus, der viele Faktoren (Indizes, Statistiken, Tabellengröße, Ressourcen usw.) berücksichtigt, um einen effektiven Ausführungsplan zu erstellen. Nach dieser Auswertung können Sie nicht sicher sagen, ob Ihre Kurzschlusslogik garantiert ist.

Ich bin vor einiger Zeit selbst auf dieselbe Frage gestoßen, und meine Forschung hat mir wirklich keine endgültige Antwort gegeben. Sie können eine kleine Abfrage schreiben, um zu beweisen, dass sie funktioniert. Sie können jedoch sicher sein, dass mit zunehmender Auslastung Ihrer Datenbank die Tabellen größer werden und die Dinge in der Datenbank optimiert und geändert werden halt. Ich konnte und habe mich daher nicht auf der Seite der Vorsicht geirrt und CASE in WHERE-Klausel verwendet, um einen Kurzschluss sicherzustellen.

Mehmet Aras
quelle
7

Sie müssen bedenken, wie Datenbanken funktionieren. Bei einer parametrisierten Abfrage erstellt die Datenbank einen Ausführungsplan basierend auf dieser Abfrage ohne die Werte für die Parameter. Diese Abfrage wird jedes Mal verwendet, wenn die Abfrage ausgeführt wird, unabhängig von den tatsächlich angegebenen Werten. Ob die Abfrage mit bestimmten Werten kurzgeschlossen wird, spielt für den Ausführungsplan keine Rolle.

Logicalmind
quelle
6
es ist wichtig für die Ausführungsgeschwindigkeit!
user4951
Nur weil es derzeit so funktioniert, heißt das nicht, dass es nicht geändert werden kann. Wir müssen Modell / Semantik von der Implementierung trennen. Ausführungspläne werden intern implementiert, um die Ausführung von Abfragen zu optimieren ... und die Kurzschlusssemantik widerspricht nicht nur der deklarativen Natur von SQL, sondern kann solche Optimierungen einschränken. Wenn jedoch die Kurzschlussbewertungssemantik vom DBMS unterstützt würde, würde sich die Implementierung von Ausführungsplänen ändern, um diese Semantik zu unterstützen.
Jorge Garcia
3

Ich benutze dies normalerweise für optionale Parameter. Ist das dasselbe wie ein Kurzschluss?

SELECT  [blah]
FROM    Emp
WHERE  ((@EmpID = -1) OR (@EmpID = EmpID))

Dies gibt mir die Möglichkeit, -1 oder was auch immer zu übergeben, um die optionale Überprüfung eines Attributs zu berücksichtigen. Manchmal umfasst dies das Verknüpfen mehrerer Tabellen oder vorzugsweise einer Ansicht.

Sehr praktisch, nicht ganz sicher, welche zusätzliche Arbeit der DB-Motor leistet.

p.campbell
quelle
2

Für SQL Server hängt es meiner Meinung nach von der Version ab, aber meiner Erfahrung mit SQL Server 2000 wird immer noch @key = t.Key ausgewertet, auch wenn @key null ist. Mit anderen Worten, bei der Bewertung der WHERE-Klausel wird kein effizienter Kurzschluss durchgeführt.

Ich habe Leute gesehen, die eine Struktur wie Ihr Beispiel empfohlen haben, um eine flexible Abfrage durchzuführen, bei der der Benutzer verschiedene Kriterien eingeben oder nicht eingeben kann. Meine Beobachtung ist, dass Key immer noch am Abfrageplan beteiligt ist, wenn @key null ist, und wenn Key indiziert ist, wird der Index nicht effizient verwendet.

Diese Art der flexiblen Abfrage mit unterschiedlichen Kriterien ist wahrscheinlich ein Fall, in dem dynamisch erstelltes SQL wirklich der beste Weg ist. Wenn @key null ist, nehmen Sie es einfach überhaupt nicht in die Abfrage auf.

Tetranz
quelle
2

Ich bin gerade über diese Frage gestolpert und habe diesen Blogeintrag bereits gefunden: http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/

Dem SQL Server steht es frei, eine Abfrage an einer beliebigen Stelle zu optimieren. In dem im Blogbeitrag angegebenen Beispiel können Sie sich also nicht auf Kurzschlüsse verlassen.

Es ist jedoch anscheinend dokumentiert, dass ein CASE in der schriftlichen Reihenfolge ausgewertet wird - überprüfen Sie die Kommentare dieses Blogposts.

stolsvik
quelle
1

Das Hauptmerkmal der Kurzschlussbewertung besteht darin, dass die Auswertung des Ausdrucks beendet wird, sobald das Ergebnis bestimmt werden kann. Das bedeutet, dass der Rest des Ausdrucks ignoriert werden kann, da das Ergebnis unabhängig davon, ob es ausgewertet wird oder nicht, dasselbe ist.

Binäre boolesche Operatoren sind komutativ und bedeuten:

a AND b == b AND a
a OR  b == b OR  a
a XOR b == b XOR a

Daher gibt es keine Garantie für die Reihenfolge der Bewertung. Die Reihenfolge der Auswertung wird vom Abfrageoptimierer festgelegt.

In Sprachen mit Objekten kann es Situationen geben, in denen Sie boolesche Ausdrücke schreiben können, die nur mit Kurzschlussauswertung ausgewertet werden können. Ihre Beispielcodekonstruktion wird häufig in solchen Sprachen (C #, Delphi, VB) verwendet. Beispielsweise:

if(someString == null | someString.Length == 0 )
  printf("no text in someString");

Dieses C # -Beispiel verursacht eine Ausnahme, wenn someString == nulles vollständig ausgewertet wird. Bei der Kurzschlussauswertung funktioniert dies jedes Mal.

SQL arbeitet nur mit skalaren Variablen (keine Objekte), die nicht nicht initialisiert werden können. Daher gibt es keine Möglichkeit, boolesche Ausdrücke zu schreiben, die nicht ausgewertet werden können. Wenn Sie einen NULL-Wert haben, gibt jeder Vergleich false zurück.

Das bedeutet, dass Sie in SQL keinen Ausdruck schreiben können, der je nach Verwendung eines Kurzschlusses oder einer vollständigen Auswertung unterschiedlich ausgewertet wird.

Wenn die SQL-Implementierung eine Kurzschlussauswertung verwendet, kann sie die Ausführung von Abfragen hoffentlich nur beschleunigen.

Zendar
quelle
1
Ja, boolesche Operatoren sind kommutativ. Ich denke nicht, dass Objekte (oder nicht) etwas damit zu tun haben.
Greg Dean
1

Ich weiß nichts über Kurzschlüsse, aber ich würde es als Wenn-Sonst-Aussage schreiben

if (@key is null)
begin

     SELECT * 
     FROM Table t 

end
else
begin

     SELECT * 
     FROM Table t 
     WHERE t.Key=@key

end

Außerdem sollten sich Variablen immer auf der rechten Seite der Gleichung befinden. das macht es sargable.

http://en.wikipedia.org/wiki/Sargable

DForck42
quelle
1
Kann jemand das über die Variablen auf der rechten Seite bestätigen? Aus irgendeinem Grund fällt es mir schwer, es zu glauben.
Greg Dean
Wie ich den Artikel verstehe. Es geht darum, dass Funktionen für Spaltennamen nicht sargbar sind. Was ich verstehe. Ich denke jedoch nicht, dass (A = @a) oder (@a = A) wichtig sind.
Greg Dean
Ich könnte falsch liegen. könnte eine gute Frage sein, wenn es noch nicht existiert.
DForck42
1

Nachfolgend ein kurzer und schmutziger Test unter SQL Server 2008 R2:

SELECT *
FROM table
WHERE 1=0
AND (function call to complex operation)

Dies wird sofort ohne Datensätze zurückgegeben. Art von Kurzschlussverhalten war vorhanden.

Dann versuchte dies:

SELECT *
FROM table
WHERE (a field from table) < 0
AND (function call to complex operation)

zu wissen, dass keine Aufzeichnung diese Bedingung erfüllen würde:

(a field from table) < 0

Dies dauerte einige Sekunden, was darauf hinwies, dass das Kurzschlussverhalten nicht mehr vorhanden war und die komplexe Operation für jeden Datensatz ausgewertet wurde.

Hoffe das hilft Jungs.

Jorge
quelle
1
Ich vermute, dass die erste Abfrage in der Kompilierungszeit "kurzgeschlossen" wurde, bevor die Ausführung des Plans tatsächlich begann.
Louis Somers
1

Hier ist eine Demo, um zu beweisen, dass MySQL die WHERE-Klausel kurzschließt :

http://rextester.com/GVE4880

Dadurch werden die folgenden Abfragen ausgeführt:

SELECT myint FROM mytable WHERE myint >= 3 OR myslowfunction('query #1', myint) = 1;
SELECT myint FROM mytable WHERE myslowfunction('query #2', myint) = 1 OR myint >= 3;

Der einzige Unterschied zwischen diesen ist die Reihenfolge der Operanden in der ODER-Bedingung.

myslowfunctionSchläft absichtlich eine Sekunde und hat den Nebeneffekt, dass bei jeder Ausführung ein Eintrag zu einer Protokolltabelle hinzugefügt wird. Hier sind die Ergebnisse dessen, was beim Ausführen der beiden oben genannten Abfragen protokolliert wird:

myslowfunction called for query #1 with value 1
myslowfunction called for query #1 with value 2
myslowfunction called for query #2 with value 1
myslowfunction called for query #2 with value 2
myslowfunction called for query #2 with value 3
myslowfunction called for query #2 with value 4

Das Obige zeigt, dass eine langsame Funktion mehrmals ausgeführt wird, wenn sie auf der linken Seite einer ODER-Bedingung erscheint, wenn der andere Operand nicht immer wahr ist (aufgrund eines Kurzschlusses).

Steve Chambers
quelle
4
Hmm, was Sie wahrscheinlich sagen wollten "Hier ist eine Demo, um zu beweisen, dass MySQL in diesem speziellen Fall eine WHERE-Klausel kurzschließt :"
TT.
1
Sicher - es ist nur ein Beweis dafür, dass es passieren kann.
Steve Chambers
0

Dies dauert im Abfrageanalysator zusätzliche 4 Sekunden, so dass, soweit ich sehen kann, IF nicht einmal kurzgeschlossen ist ...

SET @ADate = NULL

IF (@ADate IS NOT NULL)
BEGIN
    INSERT INTO #ABla VALUES (1)
        (SELECT bla from a huge view)
END

Es wäre schön, einen garantierten Weg zu haben!

bläulich
quelle
-2

Es ist jedoch offensichtlich, dass der MS SQL-Server die Kurzschlusstheorie unterstützt, um die Leistung zu verbessern, indem unnötige Überprüfungen vermieden werden.

Unterstützendes Beispiel:

SELECT 'TEST'
WHERE 1 = 'A'

SELECT 'TEST'
WHERE 1 = 1 OR 1 = 'A'

Hier würde das erste Beispiel zu dem Fehler 'Konvertierung fehlgeschlagen, wenn der Varchar-Wert' A 'in den Datentyp int konvertiert wird.'

Während die zweite Bedingung leicht ausgeführt wird, da die Bedingung 1 = 1 als WAHR ausgewertet wird und daher die zweite Bedingung überhaupt nicht ausgeführt wird.

Außerdem

SELECT 'TEST'
WHERE 1 = 0 OR 1 = 'A'

Hier würde die erste Bedingung als falsch ausgewertet, und daher würde das DBMS für die zweite Bedingung gehen, und Sie erhalten erneut den Konvertierungsfehler wie im obigen Beispiel.

HINWEIS: Ich habe den fehlerhaften Zustand nur geschrieben, um zu realisieren, ob der Zustand ausgeführt oder kurzgeschlossen wird, wenn die Abfrageergebnisse in einem Fehler den ausgeführten, anderweitig kurzgeschlossenen Zustand bedeuten.

EINFACHE ERKLÄRUNG

Erwägen,

WHERE 1 = 1 OR 2 = 2

Da die erste Bedingung auf TRUE ausgewertet wird, ist es bedeutungslos, die zweite Bedingung auszuwerten, da ihre Auswertung in einem beliebigen Wert das Ergebnis überhaupt nicht beeinflussen würde. Daher bietet sich SQL Server eine gute Gelegenheit, Zeit für die Ausführung von Abfragen zu sparen, indem unnötige Bedingungsprüfungen oder Auswertungen übersprungen werden .

Im Fall von "ODER", wenn die erste Bedingung als WAHR bewertet wird, wird die gesamte durch "ODER" verbundene Kette als wahr angesehen, ohne andere zu bewerten.

condition1 OR condition2 OR ..... OR conditionN

Wenn die Bedingung1 als wahr ausgewertet wird, ruhen Sie alle Bedingungen aus, bis die Bedingung N übersprungen wird. In verallgemeinerten Wörtern bei der Bestimmung der ersten WAHR würden alle anderen durch ODER verknüpften Bedingungen übersprungen.

Betrachten Sie die zweite Bedingung

WHERE 1 = 0 AND 1 = 1

Da die erste Bedingung auf FALSE ausgewertet wird, ist es bedeutungslos, die zweite Bedingung auszuwerten, da ihre Auswertung in einem beliebigen Wert das Ergebnis überhaupt nicht beeinflussen würde. Dies ist wiederum eine gute Gelegenheit für SQL Server, Zeit für die Ausführung von Abfragen zu sparen, indem unnötige Bedingungsprüfungen oder Auswertungen übersprungen werden .

Im Fall von "UND", wenn die erste Bedingung als FALSCH bewertet wird, wird die gesamte mit dem "UND" verbundene Kette als als FALSCH bewertet betrachtet, ohne andere zu bewerten.

condition1 AND condition2 AND ..... conditionN

wenn die condition1 zu ausgewertet wird FALSCH , alle Bedingungen bis ruhen conditionN wäre übersprungenen. In verallgemeinerten Worten bei der Bestimmung von erstem FALSE würden alle anderen durch AND verknüpften Bedingungen übersprungen.

Daher sollte ein weiser Programmierer die Bedingungskette immer so programmieren, dass weniger teure oder am weitesten entfernte Bedingungen zuerst bewertet werden oder der Zustand auf eine Weise angeordnet werden kann, die maximale Kapazität erreichen kann

RkHirpara
quelle
Downvote-Grund: Testen Sie Dinge immer auf einem realen Server mit realistischen Daten. Scheint, als ob mein vorheriger Kommentar gegessen wurde.
Jasmine