这种 Hibernate 方法效率很低吗?

Is this Hibernate method very inefficient?

此函数是我正在编写的一个 Hibernate 程序的一部分,用于为大学财务系统执行一些后端批量处理。它在程序执行时被调用了数十万次,这些调用是程序中最大的一次耗时。目前我想不出一个合理的方式来减少调用它的频率。

此函数以财政年度支付期间 ("fypper") 和该期间的一周作为参数,returns 一个存储年份、学期的结构 ("AidYearTerm") ,以及支付期周所在的术语。

public  AidYearTerm FypperTermInfo (String fypper, String week) {

    sfa_fws_calendar aidYear = new sfa_fws_calendar();      

    TypedQuery<sfa_fws_calendar> query = manager.createQuery("FROM sfa_fws_calendar cal "
            + "WHERE cal.id.fypper = ?1 AND cal.id.week_num = ?2",sfa_fws_calendar.class);
    query.setParameter(1, fypper);
    query.setParameter(2, week);

    List<sfa_fws_calendar> aidYearList = query.getResultList();

    if(!aidYearList.isEmpty()) {
        aidYear = query.getSingleResult();
    }
    else {
        aidYear.setFWS_AID_YR("9999");
        aidYear.setSEM("NOTSET");
        aidYear.setTERM("NOTSET");
        ErrorOut("Could not find term info for "+fypper);
    }
    DebugOut("found aid year "+aidYear.getFWS_AID_YR()+", term "+aidYear.getTERM());

    AidYearTerm aidYearTerm = new AidYearTerm(aidYear.getFWS_AID_YR(),aidYear.getTERM(),aidYear.getSEM()); 
    return aidYearTerm;

}

有什么我可以做的吗simpler/faster?

最简单和最明显的优化如下:

static final TypedQuery<sfa_fws_calendar> query = manager.createQuery("FROM sfa_fws_calendar cal "
        + "WHERE cal.id.fypper = ?1 AND cal.id.week_num = ?2", sfa_fws_calendar.class);

public AidYearTerm FypperTermInfo(String fypper, String week) {

    //...
    query.setParameter(1, fypper);
    query.setParameter(2, week);

    List<sfa_fws_calendar> aidYearList = query.getResultList();

不确定调用 createQuery 的开销,但这肯定只会让它发生一次。

在那之后 - 如果一切仍然在爬行中运行(这很可能)你可以考虑某种形式的缓存(也许 ehcache)但是只有当有相对较少的缓存时才有效fypper|week 组合。

乍一看:

List<sfa_fws_calendar> aidYearList = query.getResultList();

if(!aidYearList.isEmpty()) {
    aidYear = query.getSingleResult(); // <========= DON'T!!!!!
}

Query.getSingleResult() 再次运行相同的查询!

使用:

List<sfa_fws_calendar> aidYearList = query.getResultList();

if(!aidYearList.isEmpty()) {
    aidYear = aidYearList.get(0);
}

编辑:

假设您没有按年和周键控的数百万条记录,将所有需要的数据从 sfa_fws_calendar 读取到内存中一次似乎是可行的,例如读取到 Map 中,以随后避免了数以千计的数据库往返。

请注意,因为 fypperweek 实际上形成了一个(字符串)复合键,您可以构建单个 Map<String, AidYearTerm>,其中键可以是,例如 year + "_" + week。然后你的 FypperTermInfo (String fypper, String week) 将只是 return aidYearCacheMap.get(fypper + "_" + week); 和 voilà :)

这看起来非常简单 select,所以我认为这可能更像是一个围绕确保 Oracle 运行 高效运行的问题(特别是因为它 运行 成千上万每天几次)。对于这个查询,你看到什么样的解释计划?是否有完整的 table 扫描?您可能需要索引 sfa_fws_calendar table,或者如果已经有索引,请更改适当的索引并重新计算索引统计信息。

例如,类似这样的内容可能有助于更新名为 index_name:

的现有索引
ALTER INDEX index_name REBUILD COMPUTE STATISTICS;