darpet
darpet

Reputation: 3131

hibernate performance with lot of entities

I have the following line of code:

log4net.LogManager.GetLogger("m").Debug(DateTime.Now.ToString("hh:mm:ss.fff") + " Check-1");

Setting setting = session.CreateQuery("from Setting s").UniqueResult< Setting>();

log4net.LogManager.GetLogger("m").Debug(DateTime.Now.ToString("hh:mm:ss.fff") + " Check-2");

The code above executes in less than millisecond (the time in Check-1 and Check-2 is the same and it measures time in milliseconds and the criteria used is not shown in the code).

But in this case:

IList< Ticket> tickets = session.CreateQuery("from Ticket").List< Ticket>();

foreach(Ticket t in tickets)
{
t.Dosomething = 5;
log4net.LogManager.GetLogger("m").Debug(DateTime.Now.ToString("hh:mm:ss.fff") + " Check-1"); Setting setting = session.CreateQuery("from Setting s").UniqueResult< Setting>(); log4net.LogManager.GetLogger("m").Debug(DateTime.Now.ToString("hh:mm:ss.fff") + " Check-2");
}

The above code is simplified version of a huge processing code that processes a lot of data, and I needed another query in the foreach loop. The query in the forech loop executes in 500ms. The tickets collection contains 15000 rows.

I already re factored the code (no query in the foreach), but I am interested why the same query if executed alone takes no time to execute, but if executed after huge amount of entities loaded first, it becomes so slow ?

But in the same scenario above, if I use different session for the second query it executed in no time.

Any recommendations how to deal with such cases when I need to execute another query in the foreach loop of a huge amount of entities ?

Upvotes: 0

Views: 935

Answers (3)

Oskar Berggren
Oskar Berggren

Reputation: 5629

NHibernate by default tracks objects loaded in the session (first-level cache). When a query is made, NHibernate checks if some of the loaded objects have changes that may affect the outcome of the query - such changes must be flushed to the database so that the query can return correct results. The more objects loaded, the longer this process will take.

NHibernate and the ISession is optimized for having a relatively small number of loaded objects, where this is not a problem.

These are some tricks to improve the performance of batch scenarios:

  • Try to divide the work into smaller parts that can run independently in separate transactions and sessions.

  • If you have divided the work into smaller parts, you can use session.Flush() and session.Clear() at strategic points (after each independent part) to flush changes and keep the amount of tracked objects at a reasonable level. With this strategy, all parts can run in the same transaction.

  • Look at session.FlushMode to disable the auto-flush-on-query. Use FlushMode.Commitor Never combined with explicit calls to Flush(). But the result of queries might not reflect changes performed earlier in the same unit of work.

Upvotes: 2

hop
hop

Reputation: 2558

Its always better to join the two tables and get your result rather than fetching the first table records, iterating and then fetching the second table records.

Give more of you requirement

Upvotes: 0

Paul Connolly
Paul Connolly

Reputation: 371

Try loading the tickets into a DTO using a projection before iterating over them. Hibernate tracks all of the loaded objects in the session until it flushes, using a projection to load just the data you need will mean Hibernate doesn't need to load and track the objects.

Upvotes: 1

Related Questions