I'm trying to improve the performances of my asynk transactional method.
In this task I have to read almost 7500 record from a table, elaborate it, and insert/update a corresponding row in another table.
I'm using spring data jpa with hibernate.
In order to get a ScrollableResults
I inject the EntityManager
into my service.
Here how I get my ScrollableResult
object:
Session session = (Session) em.unwrap(Session.class);
ScrollableResults res = session.createQuery("from SourceTable s")
.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);
while (res.next()){
.... // em.flush() called every 40 cycles
}
Cycling on result take about 60 seconds.
And here the bottleneck. If inside my loop I execute a simple query:
query = em.createQuery("from DestTable d where d.item.id = :id", DestTable.class);
while (res.next()){
query.setParameter("id", myId).getSingleResult();
}
The execution time become x10 slower.. and takes about 600s.
I've tried to modify a parameter of my Session
or of my EntityManager
: session.setFlushMode(FlushModeType.COMMIT);
em.setFlushMode(FlushModeType.COMMIT);
It increase the performance and removing the manual flush() method the work is done in 40s!!!
So my questions are:
setFlushMode
on session
or on enityManager
?setFlushMode(FlushModeType.COMMIT);
increase in that way performance, and I cannot have same performance only by manually flushing entityManager?The problem is that the default flush mode is FlushModeType.AUTO
. In auto flush mode, Hibernate will flush before each query (only queries, not find operations). This means that in your above example, by default, Hibernate is flushing each time you call getSingleResult()
. The reason it does this is because it's possible that the changes you have made would affect the results of your query and so Hibernate wants your query to be as accurate as possible and flushes first.
You don't see the performance hit in your first example because you are only issuing one query and scrolling through it. The best solution I have found is the one you mentioned which is just to set the flush mode to COMMIT
. There should be no difference between calling setFlushMode
on the Session
or the EntityManager
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With