tags:

views:

231

answers:

2

Let me start by saying that I know that NH doesn't recommend using bulk operations. But as a bit of interest, I was wondering why this is so expensive. For 200 objects in my system, it takes 4 minutes, for which 90+% of the time is spent in DefaultAutoFlushEventListener.OnAutoFlush (Thanks to RedGate Profiler). That's insane. I wonder if anyone has written a custom DefaultAutoFlushEventListener that temporarily works around this hinderence for large repetitive updates.

Update: Actually not an issue with bulk update so much as it is with transactions and FlushMode for queries. But still, what the hell is NH doing when it flushes?

+3  A: 

This was a good one. I had each update in a transaction, and within that transaction was a query, that was 2nd level cached, but caused a flush. If you have queries in a transaction, and FlushMode=Auto (basically not turned off) you get a flush. Which is extremely expensive, especially if you have lots of objects in session cache, which we do. Moving this query out of the transaction, increased the query time by a factor of 5. Further more, making the whole thing a transaction, instead of individual transactions was a another big boost because each transaction.commit causes a flush. Updating 1000's of objects takes less than 30 seconds, and I'm too embarassed to say how long that was before. Ahh legacy code.

Update: On further investigation, I have set the FlushMode to Commit for our specific nested transaction model. Without going into too much detail, we have a specific transaction model that accounts for nested transactions when using nested 'Logic' calls. For legacy applications we don't want to set this across the board. The specific issue in this case is the combination of using Transactions and setting the FlushMode to Auto (or Always).

Trent
For production usage of NHibernate I believe the standard usage is to set FlushMode = Never in your application and then have your construct that represents your implementation of the UnitOfWork pattern to explicitly call Flush when it deems necessary.
Chris Marisic
Chris, we actually use a custom transaction model for which I think FlushMode.Commit is better. A good point nonetheless.
Trent
Do you use Spring.Data.NHibernate for nested transactions?
zvolkov
Nope, we handle our transactions specifically using something that's probably similar. In a nutshell the class is a wrapper around NH transactions that detects if there is a transaction running and has some logic to flush on inner transactions, but commit on the parent transaction.
Trent
+1  A: 

While the standard ISession is not recommended for bulk operations, you can use either a stateless session or DML instead.

Mauricio Scheffer
On further review, this actually wasn't an issue with bulk updates. I should change the title.
Trent