[JIRA] (HHH-16219) Lazy loading of association involving loading of other, eager associations leads to unwanted loading beyond max_fetch_depth
by Yoann Rodière (JIRA)
Yoann Rodière ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... ) *created* an issue
Hibernate ORM ( https://hibernate.atlassian.net/browse/HHH?atlOrigin=eyJpIjoiNjlhZDZjMjk5... ) / Bug ( https://hibernate.atlassian.net/browse/HHH-16219?atlOrigin=eyJpIjoiNjlhZD... ) HHH-16219 ( https://hibernate.atlassian.net/browse/HHH-16219?atlOrigin=eyJpIjoiNjlhZD... ) Lazy loading of association involving loading of other, eager associations leads to unwanted loading beyond max_fetch_depth ( https://hibernate.atlassian.net/browse/HHH-16219?atlOrigin=eyJpIjoiNjlhZD... )
Issue Type: Bug Affects Versions: 6.2.0.CR2 Assignee: Unassigned Components: hibernate-core Created: 22/Feb/2023 08:59 AM Fix Versions: 6.2.0 Priority: Major Reporter: Yoann Rodière ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... )
With the following model:
@Entity(name = "entitya")
public static class EntityA {
@Id
private Integer id;
@OneToOne
private EntityB entityB1;
@OneToOne
private EntityB entityB2;
// ... Getters, setters ...
}
@Entity(name = "entityb")
public static class EntityB {
@Id
private Integer id;
@OneToOne(mappedBy = "entityB1", fetch = FetchType.LAZY)
private EntityA entityA1;
@OneToOne(mappedBy = "entityB2", fetch = FetchType.LAZY)
private EntityA entityA2;
// ... Getters, setters ...
}
Assuming a max_fetch_depth of 1, calling EntityB.getEntityA1() will execute the following query:
select e2_0.id,e3_0.id,e4_0.id,e5_0.id,e6_0.id,e7_0.id
from entityb e1_0
left join entitya e2_0 on e1_0.id=e2_0.entityB1_id
left join entityb e3_0 on e3_0.id=e2_0.entityB1_id
left join entityb e4_0 on e4_0.id=e2_0.entityB2_id
left join entitya e5_0 on e1_0.id=e5_0.entityB2_id
left join entityb e6_0 on e6_0.id=e5_0.entityB1_id
left join entityb e7_0 on e7_0.id=e5_0.entityB2_id
where e1_0.id=?
That’s 6 joins, but I would have expected at most three joins, one for the lazy association and two for the eager associations in EntityA.
( https://hibernate.atlassian.net/browse/HHH-16219#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-16219#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100216- sha1:64a4cf6 )
1 year, 10 months
[JIRA] (HHH-16218) Natural id cache is extremely slow for entities with compound natural id
by Sylvain Dusart (JIRA)
Sylvain Dusart ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=63f6394... ) *created* an issue
Hibernate ORM ( https://hibernate.atlassian.net/browse/HHH?atlOrigin=eyJpIjoiZDVhMDExZTFm... ) / Bug ( https://hibernate.atlassian.net/browse/HHH-16218?atlOrigin=eyJpIjoiZDVhMD... ) HHH-16218 ( https://hibernate.atlassian.net/browse/HHH-16218?atlOrigin=eyJpIjoiZDVhMD... ) Natural id cache is extremely slow for entities with compound natural id ( https://hibernate.atlassian.net/browse/HHH-16218?atlOrigin=eyJpIjoiZDVhMD... )
Issue Type: Bug Affects Versions: 6.2.0.CR2, 6.1.6, 6.1.7 Assignee: Unassigned Attachments: CompoundNaturalIdCacheTest.java Components: hibernate-core Created: 22/Feb/2023 08:42 AM Environment: Tested on Debian 11 with official kernel (5.10.0-21-amd64) with OpenJDK 17.0.6-zulu and PostgreSQL 15 (reproduced with h2 in a test case) Labels: core Priority: Major Reporter: Sylvain Dusart ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=63f6394... )
Hibernate maintains a cache in the session for id<->naturalId correspondances (pkToNaturalIdMap and naturalIdToPkMap maps in org.hibernate.engine.internal.NaturalIdResolutionsImpl.EntityResolutions#cache).
This cache is updated after creations and loads (at least, I did not test other use-cases) .
In the maps, the natural id is encapsulated in a ResolutionImpl instance and the hashcode is computed in the constructor :
final int prime = 31;
int hashCodeCalculation = 1;
hashCodeCalculation = prime * hashCodeCalculation + entityDescriptor.hashCode();
hashCodeCalculation = prime * hashCodeCalculation + entityDescriptor.getNaturalIdMapping().calculateHashCode( naturalIdValue, persistenceContext.getSession() );
For entities with a simple natural id, entityDescriptor.getNaturalIdMapping() is an instance of SimpleNaturalIdMapping with this calculateHashCode method :
@Override
public int calculateHashCode( Object value) {
//noinspection unchecked
return value == null ? 0 : ( (JavaType< Object >) getJavaType() ).extractHashCode( value );
}
For entities with a compound natural id, entityDescriptor.getNaturalIdMapping() is an instance of CompoundNaturalIdMapping with this calculateHashCode method :
@Override
public int calculateHashCode( Object value) {
return 0;
}
As a consequence, for a given entity with a compound natural id, the hashcodes of all ResolutionImpl objects used as keys in naturalIdToPkMap are the same, which creates collisions and consumes a lot of cpu cycles.
The calculateHashCode method in CompoundNaturalIdMapping should be
@Override
public int calculateHashCode( Object value) {
return Arrays.hashCode(( Object []) value);
}
to align with the areEqual method.
The attached test case creates 20000 objects in database then re-reads these objects.
It is done for two entity classes : EntityWithSimpleNaturalId and EntityWithCompoundNaturalId.
Logs before correction :
16:33:31,782 INFO CompoundNaturalIdCacheTest:64 - Starting creations
16:33:53,745 INFO CompoundNaturalIdCacheTest:74 - Persisted 20000 EntityWithCompoundNaturalId objects, duration=21957ms
16:33:53,906 INFO CompoundNaturalIdCacheTest:83 - Persisted 20000 EntityWithSimpleNaturalId objects, duration=160ms
16:33:55,140 INFO CompoundNaturalIdCacheTest:115 - Loading at most 20000 instances of class org.hibernate.orm.test.mapping.naturalid.compound.CompoundNaturalIdCacheTest$EntityWithCompoundNaturalId
16:34:12,915 INFO CompoundNaturalIdCacheTest:123 - Loaded 20000 instances of class org.hibernate.orm.test.mapping.naturalid.compound.CompoundNaturalIdCacheTest$EntityWithCompoundNaturalId, duration=17777ms
16:34:12,921 INFO CompoundNaturalIdCacheTest:115 - Loading at most 20000 instances of class org.hibernate.orm.test.mapping.naturalid.compound.CompoundNaturalIdCacheTest$EntityWithSimpleNaturalId
16:34:13,021 INFO CompoundNaturalIdCacheTest:123 - Loaded 20000 instances of class org.hibernate.orm.test.mapping.naturalid.compound.CompoundNaturalIdCacheTest$EntityWithSimpleNaturalId, duration=99ms
Logs after correction :
16:35:37,950 INFO CompoundNaturalIdCacheTest:64 - Starting creations
16:35:38,247 INFO CompoundNaturalIdCacheTest:74 - Persisted 20000 EntityWithCompoundNaturalId objects, duration=292ms
16:35:38,368 INFO CompoundNaturalIdCacheTest:83 - Persisted 20000 EntityWithSimpleNaturalId objects, duration=119ms
16:35:39,679 INFO CompoundNaturalIdCacheTest:115 - Loading at most 20000 instances of class org.hibernate.orm.test.mapping.naturalid.compound.CompoundNaturalIdCacheTest$EntityWithCompoundNaturalId
16:35:40,096 INFO CompoundNaturalIdCacheTest:123 - Loaded 20000 instances of class org.hibernate.orm.test.mapping.naturalid.compound.CompoundNaturalIdCacheTest$EntityWithCompoundNaturalId, duration=418ms
16:35:40,103 INFO CompoundNaturalIdCacheTest:115 - Loading at most 20000 instances of class org.hibernate.orm.test.mapping.naturalid.compound.CompoundNaturalIdCacheTest$EntityWithSimpleNaturalId
16:35:40,232 INFO CompoundNaturalIdCacheTest:123 - Loaded 20000 instances of class org.hibernate.orm.test.mapping.naturalid.compound.CompoundNaturalIdCacheTest$EntityWithSimpleNaturalId, duration=129ms
( https://hibernate.atlassian.net/browse/HHH-16218#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-16218#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100216- sha1:64a4cf6 )
1 year, 10 months