Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 具有连接获取性能问题的查询_Java_Hibernate - Fatal编程技术网

Java 具有连接获取性能问题的查询

Java 具有连接获取性能问题的查询,java,hibernate,Java,Hibernate,我无法解决hibernate查询性能的问题。在下面的代码片段中,我需要选择至少具有一个映射和筛选映射的实体。我使用FETCH JOIN仅加载筛选的映射。 但在这种情况下,我的查询存在性能问题。Hibernate说警告日志: org.hibernate.hql.ast.QueryTranslatorImpl -使用集合获取指定的firstResult/maxResults;申请 记忆 当我省略FETCH JOIN并只留下JOIN查询时,速度非常快。但结果是,我将所有映射加载到实体,这对我来说是不可

我无法解决hibernate查询性能的问题。在下面的代码片段中,我需要选择至少具有一个映射和筛选映射的实体。我使用FETCH JOIN仅加载筛选的映射。 但在这种情况下,我的查询存在性能问题。Hibernate说警告日志:

org.hibernate.hql.ast.QueryTranslatorImpl -使用集合获取指定的firstResult/maxResults;申请 记忆

当我省略FETCH JOIN并只留下JOIN查询时,速度非常快。但结果是,我将所有映射加载到实体,这对我来说是不可接受的状态。有没有办法提高查询性能?映射表中有很多行

HQL查询:

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,可以将查询拆分为两个查询:

  • 使用firstResult/maxResults查询实体ID,但子表上没有“fetch”:

    select entity.id from entity (without fetch) where .... (with firstResult/maxResults)
    
  • 使用第一次查询返回的ID上的“fetch”查询实体:

    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());
        }
    }