【问题标题】:HQL query takes to long to executeHQL 查询需要很长时间才能执行
【发布时间】:2016-06-17 20:58:41
【问题描述】:

我知道要冬眠。 我有一条sql语句

SELECT VERSION_ID,D_BEGIN,D_END, 
 (SELECT NAME FROM zvit where ZVIT_ID=version.ZVIT_ID) as name  
 FROM version  
 where  VERSION_ID in  
 (SELECT term.VERSION_ID FROM term  
 where term.PERIOD_MONTH= :periodMonth and term.PERIOD_TYPE= :periodType and term.PERIOD_YEAR= :periodYear )  
 order by 1 ;

我尝试使用 createCriteria 和 HQL 来实现它。

    DetachedCriteria subQuery  = DetachedCriteria.forClass(TermData.class)
            .add(Restrictions.eq("periodmonth",  periodMonth))
            .add(Restrictions.eq("periodtype",  periodType))
            .add(Restrictions.eq("periodyear", periodYear))
            .setProjection(Projections.projectionList() 
                    .add(Projections.property("versionId.versionId"))
                    );          
    Criteria versionCriteria = session.createCriteria(VersionData.class)
            .addOrder(Order.asc("versionId"))
            .add(Subqueries.propertyIn("versionId", subQuery))
            .createAlias("zvitId", "zvitId", org.hibernate.sql.JoinType.INNER_JOIN)
            .setProjection(Projections.projectionList() 
                    .add(Projections.property("versionId"))
                    .add(Projections.property("dbegin"))
                    .add(Projections.property("dend"))
                    .add(Projections.property("zvitId.name"), "name")

                    );  

HQL:

            Query query = session.createQuery(""
                    + "from VersionData as version "
//                  + "inner join version.zvitId as zvit "
                    + "where version.versionId in "
                    + "(select term.versionId from TermData as term "
                    + "where term.periodmonth= :periodmonth and term.periodtype= :periodtype and term.periodyear= :periodyear)");

问题是这个 HQL 需要 10 倍的时间来执行。并做了很多不必要的查询。我尝试用带注释的字符串来做这件事,它有所改进,但仍然比 createCriteria 查询长 5 倍,此外我无法进行此转换

List<VersionData> queryResult = query.list(); 当我得到 VersionData 和 ZvitData 对象时。这似乎不是问题,但我仍然不明白为什么我不只收到 VersionData 对象。 但是还有一个更重要的问题是有什么方法可以改进这个 HQL 语句,使其与 mysql 或 createCriteria 查询几乎同时执行。

版本数据定义

@Entity
@Table(name = "version")
public class VersionData implements Serializable
{

    /**
     * 
     */
    private static final long serialVersionUID = 7355281418627668744L;

    @Id 
    @Column(name="VERSION_ID")  
    private String versionId;   

    /**
     * user dbegin
     */
    @Column(name = "D_BEGIN")
    @Type(type = "date")
    private Date dbegin;

    /** user dend */
    @Column(name = "D_END")
    @Type(type = "date")
    private Date dend;  


    /**
     * user zvitId
     */
    @ManyToOne
    @JoinColumn(name="ZVIT_ID") 
    private ZvitData zvitId;

    @OneToMany(targetEntity=TermData.class, mappedBy = "versionId", cascade=javax.persistence.CascadeType.ALL, fetch=FetchType.LAZY)
    private List<TermData> terms;
//getters, setters, hashcode, equals
}

【问题讨论】:

  • 亲爱的,发布您的 VersionData POJO 定义。
  • 对于每个 VersionData 都有一个 TermData 列表,因此您必须在此处添加 TermData 的定义。这是主要查询深度的导入。

标签: java mysql hibernate hql createcriteria


【解决方案1】:

好吧,使用您发布的条件查询,您只获取您需要的字段,而使用您的 HQL 查询您获取整个 Hibernate 托管实体 (VersionData)。根据该实体的配置方式,您可能会看到触发其他查询以填充该实体的字段。

您也可以使用 HQL 执行与使用标准相同的操作,并且在我看来,它比使用标准更易于理解,因此更易于维护。只需使用适当的构造函数为您希望获取的字段定义一个 java 类 MyClass,然后调用 HQL 查询,如下所示:

"select new path.to.myclass.MyClass ( "
                + " alias1.field1, "
                + " alias2.field2, "
                + " ... "

其中 aliases 是您在 HQL 查询中赋予实体的名称(例如,version 是您编写的查询中 VersionData 的别名)。没有预测,没有额外的抽象,只是一个类似 SQL 的查询。

您可以直接获取字段,然后处理返回的结果,而不是定义一个新类来保存从 HQL 查询返回的字段(我觉得这更方便),如下面的链接:

How to retrieve only certain fields of an entity in JPQL or HQL? What is the equivalent of ResultSet in JPQL or HQL?

【讨论】:

  • 这是为您希望获取的字段创建新类的常用做法吗?如果我有很多不同的查询,我不需要获取所有 VersionData 模型,与使用 createCriteria 或使用 createQuery 长期选择必要的字段相比,制作大量类和 HQL 真的有益。我真的没有维护 HQL 或 createCriteria 的经验,所以我想知道什么会更好。
  • @Evgen 您可以从VersionData 扩展MyClass 并使用结果转换器填充它。对于嵌套投影,您可以添加一些设置器。或者您可以直接将嵌套投影映射到VersionData。它需要一个特殊的定制变压器。类似FluentHibernateResultTransformer
  • 如果您不想创建很多类,请按照所示链接进行操作。另一方面,例如,字段可能对应于呈现给最终用户的列表中的行,在这种情况下,我认为将它们放在类中是有利的。至于通常的做法,我觉得 Hibernate 鼓励开发人员使用他们的标准抽象而不是使用 HQL 查询,因为前者更“面向对象”。不过,以我个人的经验,使用标准的代码比 HQL/JPQL 查询更难维护和检查正确性。
猜你喜欢
  • 2018-07-06
  • 1970-01-01
  • 2016-04-22
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 2021-06-15
  • 2011-01-17
  • 2012-12-03
相关资源
最近更新 更多