HQL查询需要很长时间才能执行

时间:2016-03-04 07:51:48

标签: java mysql hibernate hql createcriteria

我知道要冬眠。 我有一个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 Object的原因。 但更重要的问题是有没有办法改进这个HQL语句,使其与mysql或createCriteria查询同时执行。

VersionData defenition

@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
}

1 个答案:

答案 0 :(得分:1)

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

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

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

其中别名是您为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?