Linq queries on CSLA very slow..

Linq queries on CSLA very slow..

Old forum URL: forums.lhotka.net/forums/t/7750.aspx


Vinodonly posted on Thursday, October 08, 2009

I'm using very simple query on csla, something like this..

from O in TempEmpOther.OTRelInfoList
where O.InfoType == IdVal
select O.InfoValue).FirstOrDefault();


from J in TempEmpMain.JoinInfoList
where J.JoinFlag == IdVal
select J.InfoDate).FirstOrDefault();

after very slow performance i added index also on properties InfoType and JoinFlag but still the performance is very slow.. It is currently taking 60 seconds..

These queries are called from a for loop around 10 times on a bo.. total loop is for 2000 counters so 2000 X 10 times..


Bo itself is not having more then 20 records.. (most of the time it is under 10) but still performance is very slow..

can anybody help in this..

RockfordLhotka replied on Thursday, October 08, 2009

I don't know why you are seeing this type of performance. I did a test with 2000 loops over a query on a list with 30 items and it took 5 seconds. Which still seems high to me, but is a long way from 60 seconds.

I'm sure much of the perf cost is in creating the LinqBindingList, which has to add event handling to the items.

One thing you can do in a query like yours (where you don't want or need the LBL result) is to convert the original collection to an array:

var q = (from r in mylist.ToArray() where r.Id == 123 select r).FirstOrDefault();

In my test this has a major positive impact on performance.

AaronErickson replied on Thursday, October 08, 2009

There are a couple issues I see here.

I worked up the following scenario, which isolates Linq to CSLA from other factors:

  class SomeChild: BusinessBase<SomeChild>
  {
    public int SomeInt { get; set; }
  }

  class SomeList : BusinessListBase<SomeList, SomeChild>
  {
   
  }

  [TestClass]
  public class CslaQueryProviderTests
  {
    [TestMethod]
    public void performance_test_non_indexed_queries()
    {
      var normalList = new List<SomeChild>();
      normalList.AddRange(Enumerable.Range(0, 10000).Select(x => new SomeChild{ SomeInt = x }));

      var cslaList = new SomeList();
      cslaList.AddRange(Enumerable.Range(0, 10000).Select(x => new SomeChild {SomeInt = x}));

      var startNormal = DateTime.Now;
      var normalListResult = (from x in normalList where x.SomeInt == 8000 select x).First();
      var endNormal = DateTime.Now;

      var startCsla = DateTime.Now;
      var cslaListResult = (from x in cslaList where x.SomeInt == 8000 select x).First();
      var endCsla = DateTime.Now;


      var cslaTime = (endCsla - startCsla);
      var normalTime = (endNormal - startNormal);

In this test, I get the cslaTime coming to 0.5 seconds, the normal one coming to 0.1.  I also ran a variant where we use First with a predicate rather than using it after the where, and the same results occur.

There *is* a difference with CSLA where, like with any custom linq provider, each query has to be interpreted at run time, which causes some reflection overhead when the query is analyzed for whether we are going to use an index or not.  As well, when you do a select query, it actually has to generate a LinqBindingList in the interim, in case the user of the query wants to synchronize the list.

Not sure why you are getting such a perf hit - I suspect something else is going on - perf can change depending on a number of things that have to do with LinqBindingLists that we clearly can't reproduce.

That said, there is always a very clear way to not use the CSLA linq provider if that is getting in your way, and that would be to use the Enumerable static methods directly (i.e. Enumerable.First, Enumerable.Where, and so forth).  Otherwise, at this time, using a custom query provider is always going to involve some overhead because any custom provider has to use reflection to interpret the query.

RockfordLhotka replied on Thursday, October 08, 2009

My test is somewhat similar to yours, but uses the longer syntax:

 

var q = (from r in mylist where r.Id == 1234 select r).FirstOrDefault();

 

My object and list are comparable to yours, though the object uses managed properties. That’s not the issue though, because I use the same child object in my BLB and List<T> tests, so the reading-the-property-value performance is identical in both cases.

 

Rocky

 

Vinodonly replied on Saturday, October 10, 2009

Pls accept my apologies.. I rechecked this after your posts and found that problem is due to some other operation.. Linq to csla is performing properly..

Copyright (c) Marimer LLC