166

Are boolean expressions in SQL WHERE clauses short-circuit evaluated ?

For example:

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

If @key IS NULL evaluates to true, is @key IS NOT NULL AND @key = t.Key evaluated?

If no, why not?

If yes, is it guaranteed? Is it part of ANSI SQL or is it database specific?

If database specific, SQLServer? Oracle? MySQL?

Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
Greg Dean
  • 29,221
  • 14
  • 67
  • 78
  • Isn't the clause @key IS NOT NULL redundant? The @key IS NULL clause on the LHS takes care of this no? – spender Apr 25 '09 at 16:27
  • 11
    @splender - depends on the answer to the question – Greg Dean Apr 25 '09 at 16:28
  • @Greg: I agree with spender. I don't see the lack or presence of short-circuiting making any difference. If @key IS NULL, then @key = t.Key will always return false, as NULL != NULL (that's why we use IS NULL, after all). – Michael Madsen Apr 25 '09 at 16:39
  • 17
    @Michael and @spender - The point of the question is, does the second condition evaluate or not. The point of the question is not, is this specific SQL statement written in as few characters as possible. In more complicated examples it would undoubtedly matter, as if the where clause short circuits, you could write expressions that would otherwise be erroneous. – Greg Dean Apr 25 '09 at 16:49
  • If anyone still cares: `SELECT (value IS NULL) OR (value IS NOT NULL AND value='something')` returns no rows @MySQL Server 5.1.36-community – Ast Derek Jan 25 '10 at 23:49
  • Remember that SQL is a declarative language, where you don't define how something should be done. You basically describe the result you want. – Stefan Steinegger Oct 01 '12 at 13:47
  • 2
    Short circuiting implies evaluating conditions from left to right. Given a condition such as `WHERE a = 1 AND b = 2` it could be efficient for database engine to find all rows where b = 2 first, then filter where a = 1. If you ask for guarantee then optimizer becomes useless. – Salman A Dec 08 '17 at 12:01
  • In SQL Server 2017, running `DECLARE @key VARCHAR(10) = NULL; SELECT 'a' FROM LargeTable WHERE @key IS NULL OR (@key IS NOT NULL AND IndexedColumn = @key)` with an execution plan that shows an index scan. While only a simple test, it suggests that both sides of the `OR`, and both sides of the `AND` even though short-circuiting is possible. – CaptainMarvel May 23 '19 at 21:33

15 Answers15

84

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

6.3.3.3 Rule evaluation order

[...]

Where the precedence is not determined by the Formats or by parentheses, effective evaluation of expressions is generally performed from left to right. However, it is implementation-dependent whether expressions are actually evaluated left to right, particularly when operands or operators might cause conditions to be raised or if the results of the expressions can be determined without completely evaluating all parts of the expression.

Community
  • 1
  • 1
  • 7
    Implementation-dependent? Great. Good to know, too. At least `CASE` is short-circuited. – dakab Jan 07 '15 at 14:53
  • 6
    Doesn't this mean that the expression evaluations are ill-defined? "(0=0 OR NULL)", is always NULL if all terms are evaluated, but always true if evaluated left-to-right and short circuited. – user48956 Feb 25 '16 at 22:18
  • 10
    SQL is a declarative language, it basically expresses the logic of the computation without describing its control flow; which sort of contradicts the imperative style of short-circuit evaluation and its consequences. – Jorge Garcia Jun 03 '16 at 17:13
  • 1
    I hadn't thought about it that way @JorgeGarcia. I guess short-circuit evaluation does implicitly force an order on operations. I am wrestling with some code where this is possibly at the root of a subtle issue. Thanks for the insight. – Carnot Antonio Romero Sep 18 '19 at 07:25
  • 1
    @user48956 `0 = 0 or null` = `true or null` = `true`, regardless of whether it is short circuited, since `null` is semantically equal to `unknown`, and it does not matter whether the `unknown` in this disjunction was (unbeknownst to us) `true` or `false`, since `true or false` is `true`, and `true or true` is also`true`. `null or 0 = 0` would also be `true`. – allmhuran Jul 13 '22 at 15:27
66

From the above, short circuiting is not really available.

If you need it, I suggest a Case statement:

Where Case when Expr1 then Expr2 else Expr3 end = desiredResult

Expr1is always evaluated, but only one of Expr2 and Expr3 will be evaluated per row.

Jack
  • 10,943
  • 13
  • 50
  • 65
PMc
  • 661
  • 5
  • 2
  • 3
    That depends on the RDBMS's implementation I assume. For SQL Server at least, there exists at least one exception that is documented to not show this behaviour (i.e. short-circuiting); cf [CASE (Transact-SQL) - Remarks](https://msdn.microsoft.com/en-us/library/ms181765.aspx#Anchor_3). I quoted this case in [this answer](http://stackoverflow.com/a/35848730/243373) I gave on the question *Sql - Explicit order of WHERE conditions?*. – TT. Nov 15 '16 at 15:58
  • 1
    Case _expression_, not statement. – jarlh Jan 16 '18 at 13:42
19

I think this is one of the cases where I'd write it as if it didn't short-circuit, for three reasons.

  1. Because for MSSQL, it's not resolved by looking at BOL in the obvious place, so for me, that makes it canonically ambiguous.

  2. because at least then I know my code will work. And more importantly, so will those who come after me, so I'm not setting them up to worry through the same question over and over again.

  3. I write often enough for several DBMS products, and I don't want to have to remember the differences if I can work around them easily.

dkretz
  • 37,399
  • 13
  • 80
  • 138
  • 4
    Great suggestion. It doesn't answer the question, but it is a great pragmatic point of view. so +1 – Greg Dean Apr 25 '09 at 18:15
  • Agreed. But interestingly I've noticed Entity Framework will leave a short circuit logic statement intact. Not sure if that's a potential bug for this reason or if they knew something about SQL server we don't. – xr280xr Feb 12 '22 at 04:53
12

I don't believe that short circuiting in SQL Server (2005) is guaranteed. SQL Server runs your query through its optimization algorithm that takes into account a lot of things (indexes, statistics, table size, resources, etc) to come up with an effective execution plan. After this evaluation, you can't say for sure that your short circuit logic is guaranteed.

I ran into the same question myself sometime ago and my research really did not give me a definitive answer. You may write a small query to give you a sense of proof that it works but can you be sure that as the load on your database increases, the tables grow to be bigger, and things get optimized and changed in the database, that conclusion will hold. I could not and therefore erred on the side of caution and used CASE in WHERE clause to ensure short circuit.

Mehmet Aras
  • 5,284
  • 1
  • 25
  • 32
7

You have to keep in mind how databases work. Given a parameterized query the db builds an execution plan based on that query without the values for the parameters. This query is used every time the query is run regardless of what the actual supplied values are. Whether the query short-circuits with certain values will not matter to the execution plan.

Logicalmind
  • 3,436
  • 1
  • 16
  • 9
  • 6
    it matters for execution speed! – user4951 Aug 02 '11 at 13:48
  • Just because that's the way it currently work doesn't mean it cannot be changed. We have to separate model/semantics from implementation. Execution plans are implemented internally to optimize the execution of queries... and short circuit semantics not only contradict the declarative nature of SQL but may constrain such optimizations. However, If short circuit evaluation semantics were to be supported by the DBMS, the implementation of execution plans would change to support such semantics. – Jorge Garcia Jun 03 '16 at 19:10
5

I typically use this for optional parameters. Is this the same as short circuiting?

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

This gives me the option to pass in -1 or whatever to account for optional checking of an attribute. Sometimes this involves joining on multiple tables, or preferably a view.

Very handy, not entirely sure of the extra work that it gives to the db engine.

p.campbell
  • 98,673
  • 67
  • 256
  • 322
4

Just stumbled over this question, and had already found this blog-entry: http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/

The SQL server is free to optimize a query anywhere she sees fit, so in the example given in the blog post, you cannot rely on short-circuiting.

However, a CASE is apparently documented to evaluate in the written order - check the comments of that blog post.

stolsvik
  • 5,253
  • 7
  • 43
  • 52
2

For SQL Server, I think it depends on the version but my experience with SQL Server 2000 is that it still evaluates @key = t.Key even when @key is null. In other words, it does not do efficient short circuiting when evaluating the WHERE clause.

I've seen people recommending a structure like your example as a way of doing a flexible query where the user can enter or not enter various criteria. My observation is that Key is still involved in the query plan when @key is null and if Key is indexed then it does not use the index efficiently.

This sort of flexible query with varying criteria is probably one case where dynamically created SQL is really the best way to go. If @key is null then you simply don't include it in the query at all.

tetranz
  • 1,932
  • 3
  • 24
  • 32
1

Below a quick and dirty test on SQL Server 2008 R2:

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

This returns immediately with no records. Kind of short circuit behavior was present.

Then tried this:

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

knowing no record would satisfy this condition:

(a field from table) < 0

This took several seconds, indicating the short circuit behavior was not there any more and the complex operation was being evaluated for every record.

Hope this helps guys.

Jorge
  • 21
  • 1
  • 1
    My guess is that the first query was "short circuited" in compile time, before execution of the plan actually started. – Louis Somers Nov 24 '17 at 09:18
1

Here is a demo to prove that MySQL does perform WHERE clause short-circuiting:

http://rextester.com/GVE4880

This runs the following queries:

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;

The only difference between these is the order of operands in the OR condition.

myslowfunction deliberately sleeps for a second and has the side effect of adding an entry to a log table each time it is run. Here are the results of what is logged when running the above two queries:

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

The above shows that a slow function is executed more times when it appears on the left side of an OR condition when the other operand isn't always true (due to short-circuiting).

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
1

Main characteristic of short circuit evaluation is that it stops evaluating the expression as soon as the result can be determined. That means that rest of expression can be ignored because result will be same regardless it is evaluated or not.

Binary boolean operators are comutative, meaning:

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

so there is no guarantee on order of evaluation. Order of evaluation will be determined by query optimizer.

In languages with objects there can be situations where you can write boolean expressions that can be evaluated only with short circuit evaluation. Your sample code construction is often used in such languages (C#, Delphi, VB). For example:

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

This C# example will cause exception if someString == null because it will be fully evaluated. In short circuit evaluation, it will work every time.

SQL operates only on scalar variables (no objects) that cannot be uninitialized, so there is no way to write boolean expression that cannot be evaluated. If you have some NULL value, any comparison will return false.

That means that in SQL you cannot write expression that is differently evaluated depending on using short circuit or full evaluation.

If SQL implementation uses short circuit evaluation, it can only hopefully speed up query execution.

zendar
  • 13,384
  • 14
  • 59
  • 75
1

i don't know about short circuting, but i'd write it as an if-else statement

if (@key is null)
begin

     SELECT * 
     FROM Table t 

end
else
begin

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

end

also, variables should always be on the right side of the equation. this makes it sargable.

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

DForck42
  • 19,789
  • 13
  • 59
  • 84
  • 1
    Can anyone corroborate the it about the variables on the right? For some reason I have a hard time believing it. – Greg Dean Apr 27 '09 at 14:56
  • http://searchoracle.techtarget.com/expert/KnowledgebaseAnswer/0,289625,sid41_gci1267806,00.html# can't find much else right now – DForck42 Apr 27 '09 at 17:58
  • As I understand the article. It is talking about functions on column names not being sargable. Which I understand. I dont, however, think (A = @a) or (@a = A) matters. – Greg Dean Apr 28 '09 at 19:50
  • i might be wrong. might be a good question if it doesn't already exist. – DForck42 Apr 28 '09 at 19:52
0

This takes an extra 4 seconds in query analyzer, so from what I can see IF is not even shorted...

SET @ADate = NULL

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

It would be nice to have a guaranteed way!

bluish
  • 26,356
  • 27
  • 122
  • 180
-1

The quick answer is: The "short-circuit" behavior is undocumented implementation. Here's an excellent article that explains this very topic.

Understanding T-SQL Expression Short-Circuiting

ActiveX
  • 1,064
  • 1
  • 17
  • 37
-4

It is but obvious that MS Sql server supports Short circuit theory, to improve the performance by avoiding unnecessary checking,

Supporting Example:

SELECT 'TEST'
WHERE 1 = 'A'

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

Here, the first example would result into error 'Conversion failed when converting the varchar value 'A' to data type int.'

While the second runs easily as the condition 1 = 1 evaluated to TRUE and thus the second condition doesn't ran at all.

Further more

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

here the first condition would evaluate to false and hence the DBMS would go for the second condition and again you will get the error of conversion as in above example.

NOTE: I WROTE THE ERRONEOUS CONDITION JUST TO REALIZE WEATHER THE CONDITION IS EXECUTED OR SHORT-CIRCUITED IF QUERY RESULTS IN ERROR MEANS THE CONDITION EXECUTED, SHORT-CIRCUITED OTHERWISE.

SIMPLE EXPLANATION

Consider,

WHERE 1 = 1 OR 2 = 2

as the first condition is getting evaluated to TRUE, its meaningless to evaluate the second condition because its evaluation in whatever value would not affect the result at all, so its good opportunity for Sql Server to save Query Execution time by skipping unnecessary condition checking or evaluation.

in case of "OR" if first condition is evaluated to TRUE the entire chain connected by "OR" would considered as evaluated to true without evaluating others.

condition1 OR condition2 OR ..... OR conditionN

if the condition1 is evaluated to true, rest all of the conditions till conditionN would be skipped. In generalized words at determination of first TRUE, all other conditions linked by OR would be skipped.

Consider the second condition

WHERE 1 = 0 AND 1 = 1

as the first condition is getting evalutated to FALSE its meaningless to evaluate the second condition because its evaluation in whatever value would not affect the result at all, so again its good opportunity for Sql Server to save Query Execution time by skipping unnecessary condition checking or evaluation.

in case of "AND" if first condition is evaluated to FALSE the entire chain connected with the "AND" would considered as evaluated to FALSE without evaluating others.

condition1 AND condition2 AND ..... conditionN

if the condition1 is evaluated to FALSE, rest all of the conditions till conditionN would be skipped. In generalized words at determination of first FALSE, all other conditions linked by AND would be skipped.

THEREFOR, A WISE PROGRAMMER SHOULD ALWAYS PROGRAM THE CHAIN OF CONDITIONS IN SUCH A WAY THAT, LESS EXPENSIVE OR MOST ELIMINATING CONDITION GETS EVALUATED FIRST, OR ARRANGE THE CONDITION IN SUCH A WAY THAT CAN TAKE MAXIMUM BENEFIT OF SHORT CIRCUIT

RkHirpara
  • 175
  • 1
  • 5
  • 1
    Downvote reason: always test things on a real server with realistic data. Seems my previous comment got eaten. – Jasmine Nov 03 '15 at 20:11