2

I understand that && short-circuits the evaluation so it doesn’t have to evaluate the RHS if it doesn’t have to but what about EF? Is there any differences between & and && (same for | and ||)? performance-wise!

Kamran
  • 1,258
  • 1
  • 16
  • 28
  • If you need it for ef (Core or not), and you want conditions I‘d suggest to always use && or ||. Because bitwise operators are out of your experience at the moment. – Nikolaus Feb 20 '19 at 08:35

3 Answers3

7

but what about EF? Is there any differences between & and && (same for | and ||)? performance-wise!

Yes, there is.

First, sometimes EF Core uses client evaluation, so it can't be short-circuited.

Second, even when using server evaluation, EF Core translates them differently. For instance, here is the translation for SqlServer:

LINQ             SQL
==============   ============ 
expr1 && expr2   expr1 AND expr2
expr1 & expr2    (expr1 & expr2) = 1

Whether this affects the performance depends of the database query optimizer, but the first looks generally better. And some database providers which has no native support for bool type might generate quite inefficient translation or even fail to translate the & / | predicates.

Shortly, preferably always use logical && and || operators in LINQ queries.

Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • Great! But did not understand this line `so it can't be short-circuited.` – TanvirArjel Feb 20 '19 at 08:50
  • 1
    @TanvirArjel I meant, when executed client side, it uses the same evaluation rules as the corresponding C# code. e.g. `&&` and `||` will short-circuit, `&` and `|` will not. – Ivan Stoev Feb 20 '19 at 08:58
  • I have understood this ! but in case of sql server `expr1 AND expr2` does not behave the same way as C# `expr1 && expr2`? or anything else. – TanvirArjel Feb 20 '19 at 09:00
  • @TanvirArjel The *short-circuit* part makes the difference for *client evaluation*. For *server evaluation* the difference is in the SQL translation, which most likely will affect the performance due to non natural `WHERE` conditions. – Ivan Stoev Feb 20 '19 at 09:09
  • My question is : in case of `expr1 AND expr2` in SQL server , if the first operand is false, will the second operand be evaluated or not? – TanvirArjel Feb 20 '19 at 09:11
  • 2
    @TanvirArjel How the query is evaluated depends on database query optimizers and the query execution plans they create. They are allowed to do many things - reordering the conditions (in order to use index) etc, so in general you question cannot be answered. – Ivan Stoev Feb 20 '19 at 09:15
  • I am one step away of up-voting your answer :) Another question: in case of `(expr1 & expr2) = 1` in SQL server, What impact it will create in the query, I am not sure about this? – TanvirArjel Feb 20 '19 at 09:18
  • 1
    @TanvirArjel Again, how the SQL translation affects the query plan is unknown. SqlServer might be smart and treat it similar to `AND`, or might be not. And Oracle for instance would definitely have issues with both translation and execution. The point is, `AND` and `OR` are the **natural** ways of representing binary logical conditions inside SQL predicates. The idea of SQL is to describe the desired result, not *how* to do that. Which is different from LINQ to Objects where the execution depends on how you compose the query. – Ivan Stoev Feb 20 '19 at 09:27
  • Okay! Thanks you so much I shall experiment these in SQL server level. – TanvirArjel Feb 20 '19 at 09:30
2

According to Microsoft Documentation:

1.The & Operator is supported in two forms: a unary address-of operator or a binary logical operator.

Unary address-of operator:

The unary & operator returns the address of its operand. For more information, see How to: obtain the address of a variable . The address-of operator & requires unsafe context.

Integer logical bitwise AND operator:

For integer types, the & operator computes the logical bitwise AND of its operands:

uint a = 0b_1111_1000;
uint b = 0b_1001_1111;
uint c = a & b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10011000

2.The && Operator is the conditional logical AND operator, also known as the "short-circuiting" logical AND operator, computes the logical AND of its bool operands. The result of x && y is true if both x and y evaluate to true. Otherwise, the result is false. If the first operand evaluates to false, the second operand is not evaluated and the result of operation is false.The following example demonstrates that behavior:

bool SecondOperand()
{
    Console.WriteLine("Second operand is evaluated.");
    return true;
}

bool a = false && SecondOperand(); // <-- second operand is not evaluated here
Console.WriteLine(a);
// Output:
// False

bool b = true && SecondOperand(); // <-- second operand is evaluated here
Console.WriteLine(b);
// Output:
// Second operand is evaluated.
// True

Now in case of EF/EF Core behavior @Ivan Stoev explained it greatly: Here

TanvirArjel
  • 30,049
  • 14
  • 78
  • 114
2

I decided to do an experiment:

var t1 = _db.Customers
.Where(x => x.FirstName == "james" | x.FirstName == "thomas")
.Select(x=>x.CustomerId).ToList();

vs.

var t2 = _db.Customers
.Where(x => x.FirstName == "james" || x.FirstName == "thomas")
.Select(x => x.CustomerId).ToList();

t1 was executed as:

SELECT [x].[CustomerId]
FROM [Customers] AS [x]
WHERE (CASE
    WHEN [x].[FirstName] = N'james'
    THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END | CASE
    WHEN [x].[FirstName] = N'thomas'
    THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END) = 1

and t2 as :

SELECT [x].[CustomerId]
FROM [Customers] AS [x]
WHERE [x].[FirstName] IN (N'james', N'thomas')

Both returns same result. I compared their execution plan, to execute t1 I had "Index Scan" while to execute t2 I had "Index Seek". As Justin mentioned (SQL Server Plans : difference between Index Scan / Index Seek) "Seeks are always better to have than scans as they are more efficient in the way it looks data up".

So, using | or & not only it may leads to client side evaluation but it will affect the generated sql as well.

Thanks everyone!

Kamran
  • 1,258
  • 1
  • 16
  • 28