Java 具有连接获取性能问题的查询
我无法解决hibernate查询性能的问题。在下面的代码片段中,我需要选择至少具有一个映射和筛选映射的实体。我使用FETCH JOIN仅加载筛选的映射。 但在这种情况下,我的查询存在性能问题。Hibernate说警告日志: org.hibernate.hql.ast.QueryTranslatorImpl -使用集合获取指定的firstResult/maxResults;申请 记忆 当我省略FETCH JOIN并只留下JOIN查询时,速度非常快。但结果是,我将所有映射加载到实体,这对我来说是不可接受的状态。有没有办法提高查询性能?映射表中有很多行 HQL查询:Java 具有连接获取性能问题的查询,java,hibernate,Java,Hibernate,我无法解决hibernate查询性能的问题。在下面的代码片段中,我需要选择至少具有一个映射和筛选映射的实体。我使用FETCH JOIN仅加载筛选的映射。 但在这种情况下,我的查询存在性能问题。Hibernate说警告日志: org.hibernate.hql.ast.QueryTranslatorImpl -使用集合获取指定的firstResult/maxResults;申请 记忆 当我省略FETCH JOIN并只留下JOIN查询时,速度非常快。但结果是,我将所有映射加载到实体,这对我来说是不可
select distinct e from Entity
join fetch e.mappings as mapping
where e.deleted = 0 and e.mappings is not empty
and e = mapping.e and mapping.approval in (:approvals)
实体:
@Entity
@Table(name="entity")
class Entity {
...
@OneToMany(mappedBy="entity", cascade=CascadeType.REMOVE, fetch=FetchType.LAZY)
@OrderBy("created")
private List<Mapping> mappings = new ArrayList<Mapping>();
...
}
@Entity
@Table(name="mapping")
class Mapping {
public static enum MappingApproval {
WAITING, // mapping is waiting for approval
APPROVED, // mapping was approved
DECLINED; // mapping was declined
}
...
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="entity_id", nullable=false)
private Entity entity;
@Enumerated(EnumType.STRING)
@Column(name="approval", length=20)
private MappingApproval approval;
...
}
@实体
@表(name=“实体”)
类实体{
...
@OneToMany(mappedBy=“entity”,cascade=CascadeType.REMOVE,fetch=FetchType.LAZY)
@订购人(“已创建”)
私有列表映射=新的ArrayList();
...
}
@实体
@表(name=“映射”)
类映射{
公共静态枚举映射批准{
正在等待,//映射正在等待批准
已批准,//映射已批准
谢绝;//映射已谢绝
}
...
@manytone(fetch=FetchType.EAGER)
@JoinColumn(name=“entity\u id”,nullable=false)
私营实体;
@枚举(EnumType.STRING)
@列(名称=“批准”,长度=20)
私人制图审批;
...
}
感谢您在为JVM增加内存后,一切都变得更好了。毕竟,我以不使用FETCH-in查询结束。来自JPA规范 将setMaxResults或setFirstResult应用于查询的效果 未定义涉及集合上的获取联接。(JPA)企业 JavaBeans 3.0,最终版本”,Kapitel 3.6.1查询接口) Hibernate做了正确的事情,但是在内存中执行查询的一部分,速度非常慢。在我的例子中,差异在3-5毫秒到400-500毫秒之间
我的解决方案是在查询本身中实现分页。使用联接获取功能可以快速工作。如果需要具有“获取”功能的firstResult/maxResults,可以将查询拆分为两个查询:
select entity.id from entity (without fetch) where .... (with firstResult/maxResults)
select entity from entity fetch ... where id in <previous ids>
从实体提取中选择实体。。。我在哪里
之所以速度慢,是因为Hibernate执行SQL查询时根本没有分页,并且限制是在内存中完成的 然而,如果连接必须扫描和获取100k条记录,而您只对100条结果感兴趣,那么提取器所做的99.9%的工作和通过网络完成的所有I/O都只是浪费 您可以轻松地打开同时使用和分页的JPQL查询:
List<Post> posts = entityManager.createQuery("""
select p
from Post p
left join fetch p.comments
where p.title like :title
order by p.id
""", Post.class)
.setParameter("title", titlePattern)
.setMaxResults(maxResults)
.getResultList();
查询的执行方式如下:
List<Post> posts = entityManager
.createNamedQuery("PostWithCommentByRank")
.setParameter(
"titlePattern",
"High-Performance Java Persistence %"
)
.setParameter(
"rank",
5
)
.unwrap(NativeQuery.class)
.setResultTransformer(
new DistinctPostResultTransformer(entityManager)
)
.getResultList();
就这样 您能显示Hibernate发出的SQL查询吗?@axtavt我已经从Hibernate添加了SQL查询。谢谢您的时间。这是对
JOIN
或FETCH JOIN
的查询吗?另一个在哪里?@axtavt这一个用于获取连接,对于唯一的连接变量,有完全相同的查询,但没有以下映射查询。在任何奇怪的情况下,只需增加堆大小:)您应该指定如何执行此操作。这就是答案和伟大答案的区别。
List<Post> posts = entityManager
.createNamedQuery("PostWithCommentByRank")
.setParameter(
"titlePattern",
"High-Performance Java Persistence %"
)
.setParameter(
"rank",
5
)
.unwrap(NativeQuery.class)
.setResultTransformer(
new DistinctPostResultTransformer(entityManager)
)
.getResultList();
public class DistinctPostResultTransformer
extends BasicTransformerAdapter {
private final EntityManager entityManager;
public DistinctPostResultTransformer(
EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
public List transformList(
List list) {
Map<Serializable, Identifiable> identifiableMap =
new LinkedHashMap<>(list.size());
for (Object entityArray : list) {
if (Object[].class.isAssignableFrom(entityArray.getClass())) {
Post post = null;
PostComment comment = null;
Object[] tuples = (Object[]) entityArray;
for (Object tuple : tuples) {
if(tuple instanceof Identifiable) {
entityManager.detach(tuple);
if (tuple instanceof Post) {
post = (Post) tuple;
}
else if (tuple instanceof PostComment) {
comment = (PostComment) tuple;
}
else {
throw new UnsupportedOperationException(
"Tuple " + tuple.getClass() + " is not supported!"
);
}
}
}
if (post != null) {
if (!identifiableMap.containsKey(post.getId())) {
identifiableMap.put(post.getId(), post);
post.setComments(new ArrayList<>());
}
if (comment != null) {
post.addComment(comment);
}
}
}
}
return new ArrayList<>(identifiableMap.values());
}
}