Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,026 | Comments: 44,842

filter by tags archive

Challenges: Where is the optimization?

time to read 2 min | 295 words

Let us look at the following pieces of code:

public void Consume(MyBooksRequest message)
    var user = session.Get<User>(message.UserId);
    bus.Reply(new MyBooksResponse
        UserId = message.UserId,
        Timestamp = DateTime.Now,
        Books = user.CurrentlyReading.ToBookDtoArray()

public void Consume(MyQueueRequest message)
    var user = session.Get<User>(message.UserId);

    bus.Reply(new MyQueueResponse
        UserId = message.UserId,
        Timestamp = DateTime.Now,
        Queue = user.Queue.ToBookDtoArray()

public void Consume(MyRecommendationsRequest message)
    var user = session.Get<User>(message.UserId);

    bus.Reply(new MyRecommendationsResponse
        UserId = message.UserId,
        Timestamp = DateTime.Now,
        Recommendations = user.Recommendations.ToBookDtoArray()

Looking at this, I see that I have a requirement to getting my books, my queues and my recommendations. Looking at the code, can you guess how many queries are being generated to get those?

And can you suggest an optimization?


Benny Thomas

From my novise point it looks like you have 1 query for the user, and 3 lazyloading query's for the CurrentlyReading, Queue and Recommandations.

You don't need the user info, you should have a specialized query for only the things you need in each Cosume method.


An optimization would be to use a session.Load <user instead of a Get, so you would avoid that extra select as you are only using the ID.

Jason Meckley

I think Load would still query for the user,. You need to traverse the user to get to books.

Some approaches for optimization:

  1. Query the books directly rather than lazy loading from User.

  2. Eager load the books with the user

  3. Use Futures to retrieve the user/queue/recommendations at once and cache the results for a short period of time.

option 3 assumes the messages would be used in close succession/proximity to one-another. if they are not this doesn't provide much value. Although, if they were used that closely together, why not load all this information in a single consumer?


I see... I thought Load only triggered the query when navigating to a property that was not an association. Googled a little and found that it triggers the query when accessing to ANY property besides de id.

I agree with those other optimization approaches then.

Hudson Akridge

As Benny Thomas mentions, the lazy loads are going to hurt. Also, I'd imagine that you might encounter additional Select N+1 issues as you attempt to serialize to book dto's unless all of the information required for the serialization is on the object in the collection (which is not a given so I don't want to assume). Should probably join fetch any additional associations you have for those objects either in the mappings (not fantastic) or in the query you'd replace the Get() with.

As to how many queries to get those? Depends on how the ToDto() extension method is implemented. if there's additional associations that are lazy loaded, then it's 3(n), otherwise it should be 6 queries (one each to load the user, one more to load the collection on each).

Alexander Savvas

actually i find it a bit odd that you have a 'UserId" property on the MyXXXRequest classes. You could properly map the user on those, and then eagerly fetch the collections on the user (and eagerly fetching that User on the MyXXXRequest classes). That would lead to no additional queries (but that does not include the passed MyXXXRequest object)

Steve Py

I'd think these are 3 distinct requests so there's no point considering merging the fetches. Lazy-loading is the pain point in this example, you can fetch the associated collection eagerly, but I'd definitely avoid configuring them for eager-fetching, since a call to one method would pull back a lot of extra detail.

IMO though, retrieving the User is not required at all, just retrieve the relevant lists by UserID. (via HQL or Linq2NH) The user can be lazy-loaded should it be needed.

It would also depend on what the To Book DTO functionality was doing to ensure it wasn't attempting to dive the composition.

Comment preview

Comments have been closed on this topic.


No future posts left, oh my!


  1. Technical observations from my wife (3):
    13 Nov 2015 - Production issues
  2. Production postmortem (13):
    13 Nov 2015 - The case of the “it is slow on that machine (only)”
  3. Speaking (5):
    09 Nov 2015 - Community talk in Kiev, Ukraine–What does it take to be a good developer
  4. Find the bug (5):
    11 Sep 2015 - The concurrent memory buster
  5. Buffer allocation strategies (3):
    09 Sep 2015 - Bad usage patterns
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats