防止 OpenJPA N+1 在地图上选择性能问题
当我有一个包含映射的实体时,例如
@Entity
public class TestEntity {
@ElementCollection(fetch = FetchType.EAGER)
Map<String, String> strings = new HashMap<String, String>();
}
,当我选择多个实体(SELECT z FROM TestEntity z)时,OpenJPA 2.0 会对每个 TestEntity 执行一个查询来获取映射,即使我使用了 FetchType.EAGER。当 Map 值是实体并且我使用 @OneToMany 而不是 @ElementCollection 时,也会发生这种情况。原则上,通过一个查询可以更有效地完成此操作,该查询为所有返回的 TestEntities 选择所有映射条目。对于集合值字段,OpenJPA 默认情况下已经执行此操作(openjpa.jdbc.EagerFetchMode" value="parallel"),但它似乎在这个简单的实体上失败。(与 value="join" 相同的问题)。
我可以做点什么吗有没有一种简单的方法来告诉 OpenJPA 不要对每个实体执行查询而只执行一个查询? 或者是否已经计划进行任何改进此问题的工作(我将其提交到 https://issues 下。 apache.org/jira/browse/OPENJPA-1920)?
这对我们来说是一个问题,因为我们希望获取(并分离)大约 1900 个产品的列表,而使用 OpenJPA 需要花费近 15 秒的时间。我自己的本机查询只需要不到一秒钟的时间。
只需要编写一个本机查询不会有太大问题,但我们使用的映射位于可重用的 StringI18N 实体内,该实体从多个不同的实体引用(并且可以深入对象图),因此本机查询是一种维护头痛。 非常感谢任何提高性能的帮助。
编辑:显式使用 JOIN FETCH 也没有帮助: “从 TestEntity z JOIN FETCH z.strings 中选择 z” OpenJPA 的 TRACE 仍然显示它为每个单独的 TestEntity 执行一个 SQL 语句。
When I have an entity that contains a Map, e.g.
@Entity
public class TestEntity {
@ElementCollection(fetch = FetchType.EAGER)
Map<String, String> strings = new HashMap<String, String>();
}
and I select multiple entities (SELECT z FROM TestEntity z), OpenJPA 2.0 performs one query for each TestEntity to fetch the map, even though I used FetchType.EAGER. This also happens when the Map value is an entity and I use @OneToMany instead of @ElementCollection. In principle this can be done more efficiently with one query that selects all the map entries for all returned TestEntities. For Collection-valued fields OpenJPA already does this by default (openjpa.jdbc.EagerFetchMode" value="parallel") but it seems to fail on this simple entity. (Same problem with value="join").
Could I be doing something wrong? Is there an easy way to tell OpenJPA to not perform a query per entity but only one?
Or is there already any work planned on improving this (I filed it under https://issues.apache.org/jira/browse/OPENJPA-1920)?
It is a problem for us because we wish to fetch (and detach) a list of about 1900 products which takes almost 15 seconds with OpenJPA. It takes less than a second with my own native query.
Having to write only one native query wouldn't be much of a problem but the map we use is inside a reusable StringI18N entity which is referenced from several different entities (and can be deep in the object graph), so native queries are a maintenance headache.
Any help getting performance up is greatly appreciated.
EDIT: explicitly using JOIN FETCH does not help either:
"SELECT z FROM TestEntity z JOIN FETCH z.strings"
OpenJPA's TRACE still shows that it executes one SQL statement for each individual TestEntity.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这可能会很痛苦(更正:我知道这会很痛苦),但是您是否尝试过将 2 字段
TestEntity
实际映射为完整的 JPA 持久@Entity
?我知道 Hibernate 过去对待
@ElementCollection
的方式与对待@OneToMany
的方式相当不同 - OpenJPA 很可能会做类似的事情。It might be a pain (correction: I know it'll be a pain) but have you tried actually mapping your 2-field
TestEntity
as a full JPA-persisted@Entity
?I know that Hibernate used to treat
@ElementCollection
s rather differently to@OneToMany
s for example - OpenJPA could well be doing something similar.