Ayende @ Rahien

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


+972 52-548-6969

, @ Q c

Posts: 5,949 | Comments: 44,548

filter by tags archive

Challenges: Where is the optimization?

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. The RavenDB Comic Strip (3):
    28 May 2015 - Part III – High availability & sleeping soundly
  2. Special Offer (2):
    27 May 2015 - 29% discount for all our products
  3. RavenDB Sharding (3):
    22 May 2015 - Adding a new shard to an existing cluster, splitting the shard
  4. Challenge (45):
    28 Apr 2015 - What is the meaning of this change?
  5. Interview question (2):
    30 Mar 2015 - fix the index
View all series



Main feed Feed Stats
Comments feed   Comments Feed Stats