Degradation of performance after migration Hibernate 6

After migrating from hibernate 5.6.15 (Spring boot 2) to hibernate 6.6.25 (Spring boot 3) I have a degradation of performance in the application here are the metrics between the two versions when I do a saveAll(entities):

Hibernate 5.6.15

Session Metrics {

7409705 nanoseconds spent acquiring 1 JDBC connections;

0 nanoseconds spent releasing 0 JDBC connections;

43892924 nanoseconds spent preparing 4231 JDBC statements;

2427394924 nanoseconds spent executing 3117 JDBC statements;

2407533368 nanoseconds spent executing 1122 JDBC batches;

0 nanoseconds spent performing 0 L2C puts;

0 nanoseconds spent performing 0 L2C hits;

0 nanoseconds spent performing 0 L2C misses;

5073676795 nanoseconds spent executing 53 flushes (flushing a total of 193239 entities and 527360 collections);

8123499 nanoseconds spent executing 7 partial-flushes (flushing a total of 2915 entities and 2915 collections)

}

Hibernate 6.6.25

Session Metrics {

10729076 nanoseconds spent acquiring 1 JDBC connections;

0 nanoseconds spent releasing 0 JDBC connections;

4991779002 nanoseconds spent preparing 523347 JDBC statements;

442802734144 nanoseconds spent executing 522229 JDBC statements;

2675328028 nanoseconds spent executing 1351 JDBC batches;

0 nanoseconds spent performing 0 L2C puts;

0 nanoseconds spent performing 0 L2C hits;

0 nanoseconds spent performing 0 L2C misses;

43348625619 nanoseconds spent executing 53 flushes (flushing a total of 2389057 entities and 9493723 collections);

7845319 nanoseconds spent executing 3 pre-partial-flushes;

25265613 nanoseconds spent executing 9 partial-flushes (flushing a total of 4063 entities and 4063 collections)

}

Thank you!

This report is not really useful. Clearly your new application version takes a lot of time to acquire JDBC connection and also processes way more data, so clearly, there will be a difference in execution time.
If you want help, you will have to analyze this situation yourself a bit further and ask more targeted questions.

Thank you for your reply. I ran the same scenario and had the same amount of data to save (entities).

total ShiftNameEntity : 123
total VariantEntity : 0
total ShiftPartEntity : 293
total ServiceCounterEntity : 0

Here’s my code:

serviceEntityDao.saveAll(services);

I used a for loop to see the number of queries executed for each entity. I noticed that with Hibernate version 6, it executes more queries than with version 5.

for(ServiceEntity serviceEntity : services) {
serviceEntityDao.save(serviceEntity);
}

I don’t know what this saveAll method does. Please, this is a Hibernate ORM forum, so reduce the code to the Hibernate ORM primitives like EntityManager#persist/EntityManager#merge.

I finally identified the problem. Here are my two JPA entities:

Public class FirstEntity {
…
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "name", referencedColumnName = "name")
private SecondEntity firstEntity;
…
}

Public class SecondEntity {
…
@OneToMany(cascade = CascadeType.ALL, mappedBy = "firstEntity")
private List< FirstEntity > firstEntities;
…
}

The multiple queries were triggered because I declared the @OneToManyOneToMany relationship in SecondEntity.

What I don’t understand is why Hibernate 5 didn’t report this issue, but with Hibernate 6, it triggers additional queries.

After remo@OneToManying the @OneToMany relationship in SecondEntity, I no longer experienced any performance issues and the number of queries executed significantly decreased.

Thank you for your help.

I have no idea what you think you’re doing, but removing @OneToMany is probably not a solution. I suppose that your or the Spring code uses EntityManager#merge under the hood, which will trigger joining of of associations that are CascadeType.MERGE or CascadeType.ALL to get the initial state for that merge call via a select statement.
If you’re trying to insert data, consider using EntityManager#persist. If you are in fact updating existing data, you have two options. If you can change the CascadeType, then do that. Otherwise, try loading the existing data manually first and apply the changes to these objects directly instead of using EntityManager#merge. That way, you control what data is loaded explicitly and only the relevant data is flushed.

1 Like