Reputation: 3131
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
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.Commit
or 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
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
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