Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# linq order by and other statements with foreach, is there a performance difference?

I'm pogramming a lot with entity framework, collections and there with also usting where-conditions and order by actions. I've been asking myself this for a while, but never was able to figure it out.

Let say I've got the follwing two pieces of code;

EXAMPLE 1:

// An unsorted string array.
string[] letters = { "d", "c", "a", "b" };
// Use LINQ query syntax to sort the array alphabetically.
var sorted = from letter in letters
         orderby letter
         select letter;

// Loop with the foreach keyword.
foreach (string value in sorted)
{
    Console.WriteLine(value);
}

EXAMPLE 2:

// An unsorted string array.
string[] letters = { "d", "c", "a", "b" };

// Loop with the foreach keyword.
foreach (string val in letters.OrderBy(l => l))
{
    console.writeline(val)
}

The first example first does an order by on the resultset and then iterates over the collection where the second one has the order by on the moment we're going to iterate over it. Now the real question i've been wondering for a while where.. What is the difference in performance (if there is any)? And is one of the two methods better then the other one? Same with where conditons (simple and complex ones with joins), is there any notable difference?

like image 426
Rob Avatar asked Oct 20 '14 07:10

Rob


2 Answers

There is no difference between the two..

Code -

static void Main(string[] args)
{
    string[] letters = { "d", "c", "a", "b" };
    // Use LINQ query syntax to sort the array alphabetically.
    var sorted = from letter in letters
                    orderby letter
                    select letter;

    // Loop with the foreach keyword.
    foreach (string value in sorted)
    {
        Console.WriteLine(value);
    }

    foreach (string val in letters.OrderBy(letter => letter))
    {
        Console.WriteLine(val);
    }
}

Generated code -

private static void Main(string[] args)
{
  string[] strArray1 = new string[4]
  {
    "d",
    "c",
    "a",
    "b"
  };
  string[] strArray2 = strArray1;
  if (Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate2 == null)
  {
    // ISSUE: method pointer
    Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate2 = new Func<string, string>((object) null, __methodptr(\u003CMain\u003Eb__0));
  }
  Func<string, string> keySelector1 = Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate2;
  foreach (string str in (IEnumerable<string>) Enumerable.OrderBy<string, string>((IEnumerable<string>) strArray2, keySelector1))
    Console.WriteLine(str);
  string[] strArray3 = strArray1;
  if (Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate3 == null)
  {
    // ISSUE: method pointer
    Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate3 = new Func<string, string>((object) null, __methodptr(\u003CMain\u003Eb__1));
  }
  Func<string, string> keySelector2 = Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate3;
  foreach (string str in (IEnumerable<string>) Enumerable.OrderBy<string, string>((IEnumerable<string>) strArray3, keySelector2))
    Console.WriteLine(str);
}

[CompilerGenerated]
private static string \u003CMain\u003Eb__0(string letter)
{
  return letter;
}

[CompilerGenerated]
private static string \u003CMain\u003Eb__1(string letter)
{
  return letter;
}

EDIT: Here was an interesting variation I was tempted to try.. In above case, for the query expression, compiler was smart enough to optimize the Select away.. But what if, on the second variation, we tack on an explicit Select. It was kind of not surprising, but still, compiler doesn't optimize away the explicit .Select (vs explicit Select in query expression - a requirement by compiler).

Code -

    foreach (string val in letters.OrderBy(letter => letter).Select(letter => letter))
    {
        Console.WriteLine(val);
    }

Generated code -

  string[] strArray4 = strArray1;
  if (Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate6 == null)
  {
    // ISSUE: method pointer
    Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate6 = new Func<string, string>((object) null, __methodptr(\u003CMain\u003Eb__2));
  }
  Func<string, string> keySelector3 = Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate6;
  IOrderedEnumerable<string> orderedEnumerable = Enumerable.OrderBy<string, string>((IEnumerable<string>) strArray4, keySelector3);
  if (Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate7 == null)
  {
    // ISSUE: method pointer
    Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate7 = new Func<string, string>((object) null, __methodptr(\u003CMain\u003Eb__3));
  }
  Func<string, string> selector = Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate7;
  foreach (string str in Enumerable.Select<string, string>((IEnumerable<string>) orderedEnumerable, selector))
    Console.WriteLine(str);
like image 184
Vikas Gupta Avatar answered Sep 30 '22 00:09

Vikas Gupta


Your first query is equivalent to

... = letters.OrderBy(letter => letter).Select(letter => letter);

And your second query is

... in letter.OrderBy(l => l)) {

Both queries are almost identical, only the first query has an additional .Select(...) call where your select the given input, so it is pretty pointless. The C# compiler might remove the call, but you'll have to look at the generated IL to know that.

Furthermore, you first statement doesn't execute a query. .OrderBy(...), and most linq-statements, are query-definitions. This means that your call to .OrderBy(...) doesn't actually execute, its a question that is not answered until your iterate over the results. So in both your versions the queries are executed when the foreach (... in <collection>) accesses the collection it is going to iterate over.

Conclusion: the performance difference will be so small that you'll have to try very hard to even spot any real differences. Of course, that is my humble guess.

like image 27
Maarten Avatar answered Sep 30 '22 01:09

Maarten